From a5d5edc581be1ba1c598f9313e309263bc7360b3 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 17 Dec 2024 14:16:48 +0500 Subject: [PATCH 001/189] Do not trigger trailing_empty_array in tests --- clippy_lints/src/trailing_empty_array.rs | 7 +++++-- tests/ui/trailing_empty_array.rs | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index a1d92c3ac71f7..82cc5155380ea 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::has_repr_attr; +use clippy_utils::{has_repr_attr, is_in_test}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -37,7 +37,10 @@ declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]); impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { + if is_struct_with_trailing_zero_sized_array(cx, item) + && !has_repr_attr(cx, item.hir_id()) + && !is_in_test(cx.tcx, item.hir_id()) + { span_lint_and_help( cx, TRAILING_EMPTY_ARRAY, diff --git a/tests/ui/trailing_empty_array.rs b/tests/ui/trailing_empty_array.rs index 3d06c2621681d..560438b882cfe 100644 --- a/tests/ui/trailing_empty_array.rs +++ b/tests/ui/trailing_empty_array.rs @@ -192,3 +192,17 @@ type C = ConstParamNoDefault<0>; type D = ConstParamNonZeroDefault<0>; fn main() {} + +#[cfg(test)] +mod tests { + pub struct Friend { + age: u8, + } + + #[test] + fn oldest_empty_is_none() { + struct Michael { + friends: [Friend; 0], + } + } +} From 639f40568ef270e509dff2e07042f48671964413 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 17 Dec 2024 23:47:37 +0100 Subject: [PATCH 002/189] Remove obsolete comment `is_integer_const()` does the const folding. --- clippy_utils/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index d11f1a6c12f54..65c695f04ad92 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1629,7 +1629,6 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool /// Checks whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { - // FIXME: use constant folding if let ExprKind::Lit(spanned) = expr.kind { if let LitKind::Int(v, _) = spanned.node { return v == value; From 45c7ddfea6ba9980a1c6f4f9bd9c821e56af035e Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Wed, 18 Dec 2024 11:33:15 +0100 Subject: [PATCH 003/189] Implement Condvar::wait_timeout for targets without threads This always falls back to sleeping since there is no way to notify a condvar on a target without threads. --- library/std/src/sys/sync/condvar/no_threads.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs index 88ce39305e1ae..18d97d4b17ab0 100644 --- a/library/std/src/sys/sync/condvar/no_threads.rs +++ b/library/std/src/sys/sync/condvar/no_threads.rs @@ -1,4 +1,5 @@ use crate::sys::sync::Mutex; +use crate::thread::sleep; use crate::time::Duration; pub struct Condvar {} @@ -19,7 +20,8 @@ impl Condvar { panic!("condvar wait not supported") } - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - panic!("condvar wait not supported"); + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, dur: Duration) -> bool { + sleep(dur); + false } } From 872aa75867ea24e23dd4698e43c109fba260c561 Mon Sep 17 00:00:00 2001 From: Veera Date: Tue, 23 Jul 2024 13:46:38 -0400 Subject: [PATCH 004/189] Add Tests --- .../typo-in-repeat-expr-issue-80173.rs | 70 ++++++++++ .../typo-in-repeat-expr-issue-80173.stderr | 124 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs create mode 100644 tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr diff --git a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs new file mode 100644 index 0000000000000..ec0daa4e1ce98 --- /dev/null +++ b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs @@ -0,0 +1,70 @@ +#[derive(Copy, Clone)] +struct Type; + +struct NewType; + +const fn get_size() -> usize { + 10 +} + +fn get_dyn_size() -> usize { + 10 +} + +fn main() { + let a = ["a", 10]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create an array + + const size_b: usize = 20; + let b = [Type, size_b]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create an array + + let size_c: usize = 13; + let c = [Type, size_c]; + //~^ ERROR mismatched types + + const size_d: bool = true; + let d = [Type, size_d]; + //~^ ERROR mismatched types + + let e = [String::new(), 10]; + //~^ ERROR mismatched types + //~| HELP try using a conversion method + + let f = ["f", get_size()]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create an array + + let m = ["m", get_dyn_size()]; + //~^ ERROR mismatched types + + // is_vec, is_clone, is_usize_like + let g = vec![String::new(), 10]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create a vector + + let dyn_size = 10; + let h = vec![Type, dyn_size]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create a vector + + let i = vec![Type, get_dyn_size()]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create a vector + + let k = vec!['c', 10]; + //~^ ERROR mismatched types + //~| HELP replace comma with semicolon to create a vector + + let j = vec![Type, 10_u8]; + //~^ ERROR mismatched types + + let l = vec![NewType, 10]; + //~^ ERROR mismatched types + + let byte_size: u8 = 10; + let h = vec![Type, byte_size]; + //~^ ERROR mismatched types +} diff --git a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr new file mode 100644 index 0000000000000..d1bd9b590ad4e --- /dev/null +++ b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr @@ -0,0 +1,124 @@ +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:15:19 + | +LL | let a = ["a", 10]; + | ^^ expected `&str`, found integer + | +help: replace comma with semicolon to create an array + | +LL | let a = ["a"; 10]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:20:20 + | +LL | let b = [Type, size_b]; + | ^^^^^^ expected `Type`, found `usize` + | +help: replace comma with semicolon to create an array + | +LL | let b = [Type; size_b]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:25:20 + | +LL | let c = [Type, size_c]; + | ^^^^^^ expected `Type`, found `usize` + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:29:20 + | +LL | let d = [Type, size_d]; + | ^^^^^^ expected `Type`, found `bool` + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:32:29 + | +LL | let e = [String::new(), 10]; + | ^^- help: try using a conversion method: `.to_string()` + | | + | expected `String`, found integer + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:36:19 + | +LL | let f = ["f", get_size()]; + | ^^^^^^^^^^ expected `&str`, found `usize` + | +help: replace comma with semicolon to create an array + | +LL | let f = ["f"; get_size()]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:40:19 + | +LL | let m = ["m", get_dyn_size()]; + | ^^^^^^^^^^^^^^ expected `&str`, found `usize` + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:44:33 + | +LL | let g = vec![String::new(), 10]; + | ^^ expected `String`, found integer + | +help: replace comma with semicolon to create a vector + | +LL | let g = vec![String::new(); 10]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:49:24 + | +LL | let h = vec![Type, dyn_size]; + | ^^^^^^^^ expected `Type`, found integer + | +help: replace comma with semicolon to create a vector + | +LL | let h = vec![Type; dyn_size]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:53:24 + | +LL | let i = vec![Type, get_dyn_size()]; + | ^^^^^^^^^^^^^^ expected `Type`, found `usize` + | +help: replace comma with semicolon to create a vector + | +LL | let i = vec![Type; get_dyn_size()]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:57:23 + | +LL | let k = vec!['c', 10]; + | ^^ expected `char`, found `u8` + | +help: replace comma with semicolon to create a vector + | +LL | let k = vec!['c'; 10]; + | ~ + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:61:24 + | +LL | let j = vec![Type, 10_u8]; + | ^^^^^ expected `Type`, found `u8` + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:64:27 + | +LL | let l = vec![NewType, 10]; + | ^^ expected `NewType`, found integer + +error[E0308]: mismatched types + --> $DIR/typo-in-repeat-expr-issue-80173.rs:68:24 + | +LL | let h = vec![Type, byte_size]; + | ^^^^^^^^^ expected `Type`, found `u8` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0308`. From 98cc3457af5655f289dd7a9de0ff8433697ea105 Mon Sep 17 00:00:00 2001 From: Veera Date: Mon, 29 Jul 2024 13:24:26 -0400 Subject: [PATCH 005/189] Suggest Semicolon in Incorrect Repeat Expressions --- compiler/rustc_hir/src/hir.rs | 14 ++- compiler/rustc_hir_typeck/messages.ftl | 2 + compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/errors.rs | 13 +++ .../src/fn_ctxt/suggestions.rs | 90 +++++++++++++++++-- compiler/rustc_middle/src/ty/sty.rs | 14 ++- compiler/rustc_trait_selection/src/infer.rs | 6 ++ .../typo-in-repeat-expr-issue-80173.rs | 14 +-- .../typo-in-repeat-expr-issue-80173.stderr | 14 +-- 9 files changed, 144 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 398b694ae6bd6..dd8fb1f7eb6c5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,7 +7,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; use rustc_ast::{ self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, - IntTy, Label, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy, + IntTy, Label, LitIntType, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, @@ -2064,6 +2064,18 @@ impl Expr<'_> { } } + /// Check if expression is an integer literal that can be used + /// where `usize` is expected. + pub fn is_size_lit(&self) -> bool { + matches!( + self.kind, + ExprKind::Lit(Lit { + node: LitKind::Int(_, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::Usize)), + .. + }) + ) + } + /// If `Self.kind` is `ExprKind::DropTemps(expr)`, drill down until we get a non-`DropTemps` /// `Expr`. This is used in suggestions to ignore this `ExprKind` as it is semantically /// silent, only signaling the ownership system. By doing this, suggestions that check the diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index a93da52b2703c..0f424a39840a3 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -165,6 +165,8 @@ hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this ret hir_typeck_remove_semi_for_coerce_semi = the `match` is a statement because of this semicolon, consider removing it hir_typeck_remove_semi_for_coerce_suggestion = remove this semicolon +hir_typeck_replace_comma_with_semicolon = replace the comma with a semicolon to create {$descr} + hir_typeck_return_stmt_outside_of_fn_body = {$statement_kind} statement outside of function body .encl_body_label = the {$statement_kind} is part of this body... diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index e51323fc5c852..56f7a2c1150ae 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -30,7 +30,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if expr_ty == expected { return; } - self.annotate_alternative_method_deref(err, expr, error); self.explain_self_literal(err, expr, expected, expr_ty); @@ -39,6 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty) || self.suggest_remove_last_method_call(err, expr, expected) || self.suggest_associated_const(err, expr, expected) + || self.suggest_semicolon_in_repeat_expr(err, expr, expr_ty) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) || self.suggest_option_to_bool(err, expr, expr_ty, expected) || self.suggest_compatible_variants(err, expr, expected, expr_ty) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index ff09583cc65a6..4eed2bc12388d 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -846,3 +846,16 @@ pub(crate) struct PassFnItemToVariadicFunction { pub sugg_span: Span, pub replace: String, } + +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_replace_comma_with_semicolon, + applicability = "machine-applicable", + style = "verbose", + code = "; " +)] +pub(crate) struct ReplaceCommaWithSemicolon { + #[primary_span] + pub comma_span: Span, + pub descr: &'static str, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 964ef5b2106b1..c17218b611ecb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1319,14 +1319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = expr.span.shrink_to_hi(); let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) { errors::OptionResultRefMismatch::Copied { span, def_path } - } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() - && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( - self, - self.param_env, - ty, - clone_did, - ) - { + } else if self.type_is_clone_modulo_regions(self.param_env, ty) { errors::OptionResultRefMismatch::Cloned { span, def_path } } else { return false; @@ -2181,6 +2174,87 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Suggest replacing comma with semicolon in incorrect repeat expressions + /// like `["_", 10]` or `vec![String::new(), 10]`. + pub(crate) fn suggest_semicolon_in_repeat_expr( + &self, + err: &mut Diag<'_>, + expr: &hir::Expr<'_>, + expr_ty: Ty<'tcx>, + ) -> bool { + // Check if `expr` is contained in array of two elements + if let hir::Node::Expr(array_expr) = self.tcx.parent_hir_node(expr.hir_id) + && let hir::ExprKind::Array(elements) = array_expr.kind + && let [first, second] = &elements[..] + && second.hir_id == expr.hir_id + { + // Span between the two elements of the array + let comma_span = first.span.between(second.span); + + // Check if `expr` is a constant value of type `usize`. + // This can only detect const variable declarations and + // calls to const functions. + + // Checking this here instead of rustc_hir::hir because + // this check needs access to `self.tcx` but rustc_hir + // has no access to `TyCtxt`. + let expr_is_const_usize = expr_ty.is_usize() + && match expr.kind { + ExprKind::Path(QPath::Resolved( + None, + Path { res: Res::Def(DefKind::Const, _), .. }, + )) => true, + ExprKind::Call( + Expr { + kind: + ExprKind::Path(QPath::Resolved( + None, + Path { res: Res::Def(DefKind::Fn, fn_def_id), .. }, + )), + .. + }, + _, + ) => self.tcx.is_const_fn(*fn_def_id), + _ => false, + }; + + // Type of the first element is guaranteed to be checked + // when execution reaches here because `mismatched types` + // error occurs only when type of second element of array + // is not the same as type of first element. + let first_ty = self.typeck_results.borrow().expr_ty(first); + + // `array_expr` is from a macro `vec!["a", 10]` if + // 1. array expression's span is imported from a macro + // 2. first element of array implements `Clone` trait + // 3. second element is an integer literal or is an expression of `usize` like type + if self.tcx.sess.source_map().is_imported(array_expr.span) + && self.type_is_clone_modulo_regions(self.param_env, first_ty) + && (expr.is_size_lit() || expr_ty.is_usize_like()) + { + err.subdiagnostic(errors::ReplaceCommaWithSemicolon { + comma_span, + descr: "a vector", + }); + return true; + } + + // `array_expr` is from an array `["a", 10]` if + // 1. first element of array implements `Copy` trait + // 2. second element is an integer literal or is a const value of type `usize` + if self.type_is_copy_modulo_regions(self.param_env, first_ty) + && (expr.is_size_lit() || expr_is_const_usize) + { + err.subdiagnostic(errors::ReplaceCommaWithSemicolon { + comma_span, + descr: "an array", + }); + return true; + } + } + false + } + /// If the expected type is an enum (Issue #55250) with any variants whose /// sole field is of the found type, suggest such variants. (Issue #42764) pub(crate) fn suggest_compatible_variants( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 045c483d6a58a..c45238b1eb0e4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -27,7 +27,7 @@ use crate::infer::canonical::Canonical; use crate::ty::InferTy::*; use crate::ty::{ self, AdtDef, BoundRegionKind, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, - Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, + Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, }; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here @@ -1008,6 +1008,18 @@ impl<'tcx> Ty<'tcx> { } } + /// Check if type is an `usize`. + #[inline] + pub fn is_usize(self) -> bool { + matches!(self.kind(), Uint(UintTy::Usize)) + } + + /// Check if type is an `usize` or an integral type variable. + #[inline] + pub fn is_usize_like(self) -> bool { + matches!(self.kind(), Uint(UintTy::Usize) | Infer(IntVar(_))) + } + #[inline] pub fn is_never(self) -> bool { matches!(self.kind(), Never) diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index ee708564a8046..f373706b2960c 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -47,6 +47,12 @@ impl<'tcx> InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } + fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { + let ty = self.resolve_vars_if_possible(ty); + let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) + } + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) diff --git a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs index ec0daa4e1ce98..c76e7a1d71665 100644 --- a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs +++ b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.rs @@ -14,12 +14,12 @@ fn get_dyn_size() -> usize { fn main() { let a = ["a", 10]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create an array + //~| HELP replace the comma with a semicolon to create an array const size_b: usize = 20; let b = [Type, size_b]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create an array + //~| HELP replace the comma with a semicolon to create an array let size_c: usize = 13; let c = [Type, size_c]; @@ -35,7 +35,7 @@ fn main() { let f = ["f", get_size()]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create an array + //~| HELP replace the comma with a semicolon to create an array let m = ["m", get_dyn_size()]; //~^ ERROR mismatched types @@ -43,20 +43,20 @@ fn main() { // is_vec, is_clone, is_usize_like let g = vec![String::new(), 10]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create a vector + //~| HELP replace the comma with a semicolon to create a vector let dyn_size = 10; let h = vec![Type, dyn_size]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create a vector + //~| HELP replace the comma with a semicolon to create a vector let i = vec![Type, get_dyn_size()]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create a vector + //~| HELP replace the comma with a semicolon to create a vector let k = vec!['c', 10]; //~^ ERROR mismatched types - //~| HELP replace comma with semicolon to create a vector + //~| HELP replace the comma with a semicolon to create a vector let j = vec![Type, 10_u8]; //~^ ERROR mismatched types diff --git a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr index d1bd9b590ad4e..95eddbde9e672 100644 --- a/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr +++ b/tests/ui/repeat-expr/typo-in-repeat-expr-issue-80173.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let a = ["a", 10]; | ^^ expected `&str`, found integer | -help: replace comma with semicolon to create an array +help: replace the comma with a semicolon to create an array | LL | let a = ["a"; 10]; | ~ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | let b = [Type, size_b]; | ^^^^^^ expected `Type`, found `usize` | -help: replace comma with semicolon to create an array +help: replace the comma with a semicolon to create an array | LL | let b = [Type; size_b]; | ~ @@ -46,7 +46,7 @@ error[E0308]: mismatched types LL | let f = ["f", get_size()]; | ^^^^^^^^^^ expected `&str`, found `usize` | -help: replace comma with semicolon to create an array +help: replace the comma with a semicolon to create an array | LL | let f = ["f"; get_size()]; | ~ @@ -63,7 +63,7 @@ error[E0308]: mismatched types LL | let g = vec![String::new(), 10]; | ^^ expected `String`, found integer | -help: replace comma with semicolon to create a vector +help: replace the comma with a semicolon to create a vector | LL | let g = vec![String::new(); 10]; | ~ @@ -74,7 +74,7 @@ error[E0308]: mismatched types LL | let h = vec![Type, dyn_size]; | ^^^^^^^^ expected `Type`, found integer | -help: replace comma with semicolon to create a vector +help: replace the comma with a semicolon to create a vector | LL | let h = vec![Type; dyn_size]; | ~ @@ -85,7 +85,7 @@ error[E0308]: mismatched types LL | let i = vec![Type, get_dyn_size()]; | ^^^^^^^^^^^^^^ expected `Type`, found `usize` | -help: replace comma with semicolon to create a vector +help: replace the comma with a semicolon to create a vector | LL | let i = vec![Type; get_dyn_size()]; | ~ @@ -96,7 +96,7 @@ error[E0308]: mismatched types LL | let k = vec!['c', 10]; | ^^ expected `char`, found `u8` | -help: replace comma with semicolon to create a vector +help: replace the comma with a semicolon to create a vector | LL | let k = vec!['c'; 10]; | ~ From 15ab2ff55adbacb263190f74aba8735c129db420 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 21 Dec 2024 21:09:40 +0100 Subject: [PATCH 006/189] use the correct `ParamEnv` when checking future's return type in `missing_errors_doc` --- clippy_lints/src/doc/missing_headers.rs | 11 +++++++++-- tests/ui/crashes/ice-13862.rs | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 tests/ui/crashes/ice-13862.rs diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 40377dd841e0c..3e2b7055de4d0 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -1,6 +1,6 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{implements_trait_with_env, is_type_diagnostic_item}; use clippy_utils::{is_doc_hidden, return_ty}; use rustc_hir::{BodyId, FnSig, OwnerId, Safety}; use rustc_lint::LateContext; @@ -70,7 +70,14 @@ pub fn check( && let typeck = cx.tcx.typeck_body(body_id) && let body = cx.tcx.hir().body(body_id) && let ret_ty = typeck.expr_ty(body.value) - && implements_trait(cx, ret_ty, future, &[]) + && implements_trait_with_env( + cx.tcx, + ty::TypingEnv::non_body_analysis(cx.tcx, owner_id.def_id), + ret_ty, + future, + Some(owner_id.def_id.to_def_id()), + &[], + ) && let ty::Coroutine(_, subs) = ret_ty.kind() && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) { diff --git a/tests/ui/crashes/ice-13862.rs b/tests/ui/crashes/ice-13862.rs new file mode 100644 index 0000000000000..a5f010054b2f9 --- /dev/null +++ b/tests/ui/crashes/ice-13862.rs @@ -0,0 +1,19 @@ +#![crate_type = "lib"] +#![no_std] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +pub struct S; + +impl Future for S { + type Output = (); + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { + todo!() + } +} + +pub fn f() -> S { + S +} From 7218fd19e035b54918336b6cd027e6b407ffa540 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 22 Dec 2024 19:48:33 +0800 Subject: [PATCH 007/189] Impl String::into_chars Signed-off-by: tison --- library/alloc/src/string.rs | 187 +++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 23d060d2158cd..0c9535dfaa628 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -62,10 +62,10 @@ use crate::alloc::Allocator; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, Chars, Utf8Error, from_utf8_unchecked_mut}; +use crate::str::{self, CharIndices, Chars, Utf8Error, from_utf8_unchecked_mut}; #[cfg(not(no_global_oom_handling))] use crate::str::{FromStr, from_boxed_utf8_unchecked}; -use crate::vec::Vec; +use crate::vec::{self, Vec}; /// A UTF-8–encoded, growable string. /// @@ -1952,6 +1952,61 @@ impl String { Drain { start, end, iter: chars_iter, string: self_ptr } } + /// Converts a `String` into an iterator over the [`char`]s of the string. + /// + /// As a string consists of valid UTF-8, we can iterate through a string + /// by [`char`]. This method returns such an iterator. + /// + /// It's important to remember that [`char`] represents a Unicode Scalar + /// Value, and might not match your idea of what a 'character' is. Iteration + /// over grapheme clusters may be what you actually want. That functionality + /// is not provided by Rust's standard library, check crates.io instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let word = String::from("goodbye"); + /// + /// let mut chars = word.into_chars(); + /// + /// assert_eq!(Some('g'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('d'), chars.next()); + /// assert_eq!(Some('b'), chars.next()); + /// assert_eq!(Some('y'), chars.next()); + /// assert_eq!(Some('e'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// Remember, [`char`]s might not match your intuition about characters: + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let y = String::from("y̆"); + /// + /// let mut chars = y.into_chars(); + /// + /// assert_eq!(Some('y'), chars.next()); // not 'y̆' + /// assert_eq!(Some('\u{0306}'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// [`char`]: prim@char + #[inline] + #[must_use = "`self` will be dropped if the result is not used"] + #[unstable(feature = "string_into_chars", issue = "133125")] + pub fn into_chars(self) -> IntoChars { + IntoChars { bytes: self.into_bytes().into_iter() } + } + /// Removes the specified range in the string, /// and replaces it with the given string. /// The given string doesn't need to be the same length as the range. @@ -3090,6 +3145,134 @@ impl fmt::Write for String { } } +/// An iterator over the [`char`]s of a string. +/// +/// This struct is created by the [`into_chars`] method on [`String`]. +/// See its documentation for more. +/// +/// [`char`]: prim@char +/// [`into_chars`]: String::into_chars +#[cfg_attr(not(no_global_oom_handling), derive(Clone))] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "string_into_chars", issue = "133125")] +pub struct IntoChars { + bytes: vec::IntoIter, +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl fmt::Debug for IntoChars { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IntoChars").field(&self.as_str()).finish() + } +} + +impl IntoChars { + /// Views the underlying data as a subslice of the original data. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let mut chars = String::from("abc").into_chars(); + /// + /// assert_eq!(chars.as_str(), "abc"); + /// chars.next(); + /// assert_eq!(chars.as_str(), "bc"); + /// chars.next(); + /// chars.next(); + /// assert_eq!(chars.as_str(), ""); + /// ``` + #[unstable(feature = "string_into_chars", issue = "133125")] + #[must_use] + #[inline] + pub fn as_str(&self) -> &str { + // SAFETY: `bytes` is a valid UTF-8 string. + unsafe { str::from_utf8_unchecked(self.bytes.as_slice()) } + } + + /// Consumes the `IntoChars`, returning the remaining string. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_into_chars)] + /// + /// let chars = String::from("abc").into_chars(); + /// assert_eq!(chars.into_string(), "abc"); + /// + /// let mut chars = String::from("def").into_chars(); + /// chars.next(); + /// assert_eq!(chars.into_string(), "ef"); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_into_chars", issue = "133125")] + #[inline] + pub fn into_string(self) -> String { + // Safety: `bytes` are kept in UTF-8 form, only removing whole `char`s at a time. + unsafe { String::from_utf8_unchecked(self.bytes.collect()) } + } + + #[inline] + fn iter(&self) -> CharIndices<'_> { + self.as_str().char_indices() + } +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl Iterator for IntoChars { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + let mut iter = self.iter(); + match iter.next() { + None => None, + Some((_, ch)) => { + let offset = iter.offset(); + // `offset` is a valid index. + let _ = self.bytes.advance_by(offset); + Some(ch) + } + } + } + + #[inline] + fn count(self) -> usize { + self.iter().count() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter().size_hint() + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl DoubleEndedIterator for IntoChars { + #[inline] + fn next_back(&mut self) -> Option { + let len = self.as_str().len(); + let mut iter = self.iter(); + match iter.next_back() { + None => None, + Some((idx, ch)) => { + // `idx` is a valid index. + let _ = self.bytes.advance_back_by(len - idx); + Some(ch) + } + } + } +} + +#[unstable(feature = "string_into_chars", issue = "133125")] +impl FusedIterator for IntoChars {} + /// A draining iterator for `String`. /// /// This struct is created by the [`drain`] method on [`String`]. See its From de863026912d9fa86db10003825273697218a6e4 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Mon, 23 Dec 2024 00:44:15 +0900 Subject: [PATCH 008/189] correct suggestion for manual_div_ceil lint --- clippy_lints/src/manual_div_ceil.rs | 38 ++++++++++- tests/ui/manual_div_ceil.fixed | 22 +++++++ tests/ui/manual_div_ceil.rs | 22 +++++++ tests/ui/manual_div_ceil.stderr | 56 +++++++++++++++- tests/ui/manual_div_ceil_with_feature.fixed | 27 ++++++++ tests/ui/manual_div_ceil_with_feature.rs | 27 ++++++++ tests/ui/manual_div_ceil_with_feature.stderr | 68 +++++++++++++++++++- 7 files changed, 255 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index bbb89bee8355d..aa59b047b169a 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -2,14 +2,15 @@ use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::sugg::Sugg; -use rustc_ast::{BinOpKind, LitKind}; +use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self}; use rustc_session::impl_lint_pass; +use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use clippy_config::Conf; @@ -138,9 +139,40 @@ fn build_suggestion( applicability: &mut Applicability, ) { let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par(); + let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric() + && matches!( + lhs.kind, + ExprKind::Lit(Spanned { + node: LitKind::Int(_, LitIntType::Unsuffixed), + .. + }) | ExprKind::Unary(UnOp::Neg, Expr { + kind: ExprKind::Lit(Spanned { + node: LitKind::Int(_, LitIntType::Unsuffixed), + .. + }), + .. + }) + ) { + format!("_{}", cx.typeck_results().expr_ty(rhs)) + } else { + String::new() + }; + let dividend_sugg_str = dividend_sugg.into_string(); + // If `dividend_sugg` has enclosing paren like `(-2048)` and we need to add type suffix in the + // suggestion message, we want to make a suggestion string before `div_ceil` like + // `(-2048_{type_suffix})`. + let suggestion_before_div_ceil = if has_enclosing_paren(÷nd_sugg_str) { + format!( + "{}{})", + ÷nd_sugg_str[..dividend_sugg_str.len() - 1].to_string(), + type_suffix + ) + } else { + format!("{dividend_sugg_str}{type_suffix}") + }; let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); - let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})"); + let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"); span_lint_and_sugg( cx, diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed index e7801f7376aaf..1fb1df5b44253 100644 --- a/tests/ui/manual_div_ceil.fixed +++ b/tests/ui/manual_div_ceil.fixed @@ -28,3 +28,25 @@ fn main() { let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; } + +fn issue_13843() { + let x = 3usize; + let _ = 2048_usize.div_ceil(x); + + let x = 5usize; + let _ = 2048usize.div_ceil(x); + + let x = 5usize; + let _ = 2048_usize.div_ceil(x); + + let x = 2048usize; + let _ = x.div_ceil(4); + + let _: u32 = 2048_u32.div_ceil(6); + let _: usize = 2048_usize.div_ceil(6); + let _: u32 = 0x2048_u32.div_ceil(0x6); + + let _ = 2048_u32.div_ceil(6u32); + + let _ = 1_000_000_u32.div_ceil(6u32); +} diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs index 2de74c7eaa881..4f6d38f0d1450 100644 --- a/tests/ui/manual_div_ceil.rs +++ b/tests/ui/manual_div_ceil.rs @@ -28,3 +28,25 @@ fn main() { let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; } + +fn issue_13843() { + let x = 3usize; + let _ = (2048 + x - 1) / x; + + let x = 5usize; + let _ = (2048usize + x - 1) / x; + + let x = 5usize; + let _ = (2048_usize + x - 1) / x; + + let x = 2048usize; + let _ = (x + 4 - 1) / 4; + + let _: u32 = (2048 + 6 - 1) / 6; + let _: usize = (2048 + 6 - 1) / 6; + let _: u32 = (0x2048 + 0x6 - 1) / 0x6; + + let _ = (2048 + 6u32 - 1) / 6u32; + + let _ = (1_000_000 + 6u32 - 1) / 6u32; +} diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr index dc652dff405f2..3d87fe8e04090 100644 --- a/tests/ui/manual_div_ceil.stderr +++ b/tests/ui/manual_div_ceil.stderr @@ -31,5 +31,59 @@ error: manually reimplementing `div_ceil` LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` -error: aborting due to 5 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:34:13 + | +LL | let _ = (2048 + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:37:13 + | +LL | let _ = (2048usize + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:40:13 + | +LL | let _ = (2048_usize + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:43:13 + | +LL | let _ = (x + 4 - 1) / 4; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:45:18 + | +LL | let _: u32 = (2048 + 6 - 1) / 6; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:46:20 + | +LL | let _: usize = (2048 + 6 - 1) / 6; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:47:18 + | +LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:49:13 + | +LL | let _ = (2048 + 6u32 - 1) / 6u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:51:13 + | +LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` + +error: aborting due to 14 previous errors diff --git a/tests/ui/manual_div_ceil_with_feature.fixed b/tests/ui/manual_div_ceil_with_feature.fixed index a1d678c66898c..f32b78aa14d08 100644 --- a/tests/ui/manual_div_ceil_with_feature.fixed +++ b/tests/ui/manual_div_ceil_with_feature.fixed @@ -23,3 +23,30 @@ fn main() { let _ = (x + (y - 1)) / z; } + +fn issue_13843() { + let x = 3usize; + let _ = 2048_usize.div_ceil(x); + + let x = 5usize; + let _ = 2048usize.div_ceil(x); + + let x = 5usize; + let _ = 2048_usize.div_ceil(x); + + let x = 2048usize; + let _ = x.div_ceil(4); + + let _ = 2048_i32.div_ceil(4); + + let _: u32 = 2048_u32.div_ceil(6); + let _: usize = 2048_usize.div_ceil(6); + let _: u32 = 0x2048_u32.div_ceil(0x6); + + let _ = 2048_u32.div_ceil(6u32); + + let x = -2; + let _ = (-2048_i32).div_ceil(x); + + let _ = 1_000_000_u32.div_ceil(6u32); +} diff --git a/tests/ui/manual_div_ceil_with_feature.rs b/tests/ui/manual_div_ceil_with_feature.rs index 58cb1dbe34d1c..54d89fcbd4622 100644 --- a/tests/ui/manual_div_ceil_with_feature.rs +++ b/tests/ui/manual_div_ceil_with_feature.rs @@ -23,3 +23,30 @@ fn main() { let _ = (x + (y - 1)) / z; } + +fn issue_13843() { + let x = 3usize; + let _ = (2048 + x - 1) / x; + + let x = 5usize; + let _ = (2048usize + x - 1) / x; + + let x = 5usize; + let _ = (2048_usize + x - 1) / x; + + let x = 2048usize; + let _ = (x + 4 - 1) / 4; + + let _ = (2048 + 4 - 1) / 4; + + let _: u32 = (2048 + 6 - 1) / 6; + let _: usize = (2048 + 6 - 1) / 6; + let _: u32 = (0x2048 + 0x6 - 1) / 0x6; + + let _ = (2048 + 6u32 - 1) / 6u32; + + let x = -2; + let _ = (-2048 + x - 1) / x; + + let _ = (1_000_000 + 6u32 - 1) / 6u32; +} diff --git a/tests/ui/manual_div_ceil_with_feature.stderr b/tests/ui/manual_div_ceil_with_feature.stderr index 361ef9bd9f42a..c5e8c1a687cd8 100644 --- a/tests/ui/manual_div_ceil_with_feature.stderr +++ b/tests/ui/manual_div_ceil_with_feature.stderr @@ -43,5 +43,71 @@ error: manually reimplementing `div_ceil` LL | let _ = (z_u + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)` -error: aborting due to 7 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:29:13 + | +LL | let _ = (2048 + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:32:13 + | +LL | let _ = (2048usize + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:35:13 + | +LL | let _ = (2048_usize + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:38:13 + | +LL | let _ = (x + 4 - 1) / 4; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:40:13 + | +LL | let _ = (2048 + 4 - 1) / 4; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_i32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:42:18 + | +LL | let _: u32 = (2048 + 6 - 1) / 6; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:43:20 + | +LL | let _: usize = (2048 + 6 - 1) / 6; + | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:44:18 + | +LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:46:13 + | +LL | let _ = (2048 + 6u32 - 1) / 6u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:49:13 + | +LL | let _ = (-2048 + x - 1) / x; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(-2048_i32).div_ceil(x)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:51:13 + | +LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` + +error: aborting due to 18 previous errors From 5065a91d7fc4c7528a310bdb865b5a567e31e737 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 21 Dec 2024 16:36:18 +0100 Subject: [PATCH 009/189] Improve prose around `as_slice` example of IterMut I've removed the cryptic message about not being able to call `&mut self` methods while retaining a shared borrow of the iterator, such as `as_slice` produces. This is just normal borrowing rules and does not seem especially relevant here. I can whip up a replacement if someone thinks it has value. --- library/core/src/slice/iter.rs | 42 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index d2842f69008e2..a687ed7129dc8 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -49,7 +49,7 @@ impl<'a, T> IntoIterator for &'a mut [T] { /// // First, we need a slice to call the `iter` method on: /// let slice = &[1, 2, 3]; /// -/// // Then we call `iter` on the slice to get the `Iter` struct, +/// // Then we call `iter` on the slice to get the `Iter` iterator, /// // and iterate over it: /// for element in slice.iter() { /// println!("{element}"); @@ -107,24 +107,20 @@ impl<'a, T> Iter<'a, T> { /// Views the underlying data as a subslice of the original data. /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// /// # Examples /// /// Basic usage: /// /// ``` /// // First, we need a slice to call the `iter` method on: - /// // struct (`&[usize]` here): /// let slice = &[1, 2, 3]; /// - /// // Then we call `iter` on the slice to get the `Iter` struct: + /// // Then we call `iter` on the slice to get the `Iter` iterator: /// let mut iter = slice.iter(); /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]": /// println!("{:?}", iter.as_slice()); /// - /// // Now, we call the `next` method to remove the first element of the iterator: + /// // Now, we call the `next` method to remove the first element from the iterator: /// iter.next(); /// // Here the iterator does not contain the first element of the slice any more, /// // so `as_slice` only returns the last two elements of the slice, @@ -181,7 +177,7 @@ impl AsRef<[T]> for Iter<'_, T> { /// // First, we need a slice to call the `iter_mut` method on: /// let slice = &mut [1, 2, 3]; /// -/// // Then we call `iter_mut` on the slice to get the `IterMut` struct, +/// // Then we call `iter_mut` on the slice to get the `IterMut` iterator, /// // iterate over it and increment each element value: /// for element in slice.iter_mut() { /// *element += 1; @@ -286,25 +282,30 @@ impl<'a, T> IterMut<'a, T> { /// Views the underlying data as a subslice of the original data. /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// /// # Examples /// /// Basic usage: /// /// ``` - /// let mut slice: &mut [usize] = &mut [1, 2, 3]; + /// // First, we need a slice to call the `iter_mut` method on: + /// let slice = &mut [1, 2, 3]; /// - /// // First, we get the iterator: + /// // Then we call `iter_mut` on the slice to get the `IterMut` iterator: /// let mut iter = slice.iter_mut(); - /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": - /// assert_eq!(iter.as_slice(), &[1, 2, 3]); + /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]": + /// println!("{:?}", iter.as_slice()); /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// assert_eq!(iter.as_slice(), &[2, 3]); + /// // Now, we call the `next` method to remove the first element from the iterator + /// // and increment its value: + /// *iter.next().unwrap() += 1; + /// // Here the iterator does not contain the first element of the slice any more, + /// // so `as_slice` only returns the last two elements of the slice, + /// // and so this prints "[2, 3]": + /// println!("{:?}", iter.as_slice()); + /// + /// // The underlying slice still contains three elements, but its first element + /// // was increased by 1, so this prints "[2, 2, 3]": + /// println!("{:?}", slice); /// ``` #[must_use] #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] @@ -315,9 +316,6 @@ impl<'a, T> IterMut<'a, T> { /// Views the underlying data as a mutable subslice of the original data. /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// /// # Examples /// /// Basic usage: From 71f1a8702d859dce1b85a021105132962a593d42 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Tue, 24 Dec 2024 18:44:34 +0900 Subject: [PATCH 010/189] remove known problems section from match_same_arms --- clippy_lints/src/matches/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 1fd2ebcb54a68..ac1eae07eff63 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -583,11 +583,6 @@ declare_clippy_lint! { /// are the same on purpose, you can factor them /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). /// - /// ### Known problems - /// False positive possible with order dependent `match` - /// (see issue - /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)). - /// /// ### Example /// ```rust,ignore /// match foo { From be09596df901c094f803abacc4aa81e1d45c8e3b Mon Sep 17 00:00:00 2001 From: alexey semenyuk Date: Tue, 24 Dec 2024 18:36:10 +0500 Subject: [PATCH 011/189] Examples fixes for regex --- clippy_lints/src/regex.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 6a5bf1b8045d5..2f77989b379fa 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -24,6 +24,11 @@ declare_clippy_lint! { /// ```ignore /// Regex::new("(") /// ``` + /// + /// Use instead: + /// ```ignore + /// Regex::new("\(") + /// ``` #[clippy::version = "pre 1.29.0"] pub INVALID_REGEX, correctness, @@ -49,6 +54,11 @@ declare_clippy_lint! { /// ```ignore /// Regex::new("^foobar") /// ``` + /// + /// Use instead: + /// ```ignore + /// str::starts_with("foobar") + /// ``` #[clippy::version = "pre 1.29.0"] pub TRIVIAL_REGEX, nursery, From 1cc50519d103c84ec68f466af17c728e4584087e Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 26 Dec 2024 15:01:07 +0100 Subject: [PATCH 012/189] Merge commit '609cd310be44677ae31d452a17b0f8207e1abfe1' into clippy-subtree-update --- CHANGELOG.md | 5 + .../development/common_tools_writing_lints.md | 2 +- .../development/infrastructure/backport.md | 126 ++-- .../src/development/infrastructure/release.md | 128 ++-- book/src/development/infrastructure/sync.md | 41 +- book/src/development/the_team.md | 2 +- book/src/development/type_checking.md | 2 +- book/src/lint_configuration.md | 10 + clippy_config/src/conf.rs | 3 + .../src/arbitrary_source_item_ordering.rs | 2 +- clippy_lints/src/attrs/mod.rs | 41 ++ clippy_lints/src/attrs/repr_attributes.rs | 43 ++ clippy_lints/src/attrs/useless_attribute.rs | 22 +- clippy_lints/src/attrs/utils.rs | 21 +- clippy_lints/src/booleans.rs | 2 +- .../src/casts/as_pointer_underscore.rs | 19 + clippy_lints/src/casts/borrow_as_ptr.rs | 35 +- clippy_lints/src/casts/mod.rs | 51 +- clippy_lints/src/comparison_chain.rs | 16 +- clippy_lints/src/declared_lints.rs | 4 + clippy_lints/src/default_numeric_fallback.rs | 7 +- clippy_lints/src/dereference.rs | 11 +- clippy_lints/src/derive.rs | 8 +- clippy_lints/src/disallowed_macros.rs | 1 - clippy_lints/src/disallowed_methods.rs | 2 - .../src/doc/include_in_doc_without_cfg.rs | 4 +- clippy_lints/src/doc/mod.rs | 116 +++- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/functions/mod.rs | 11 +- clippy_lints/src/functions/must_use.rs | 58 +- clippy_lints/src/functions/result.rs | 29 +- clippy_lints/src/if_not_else.rs | 54 +- clippy_lints/src/incompatible_msrv.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 36 +- clippy_lints/src/indexing_slicing.rs | 44 +- clippy_lints/src/large_include_file.rs | 4 +- clippy_lints/src/lib.rs | 7 +- clippy_lints/src/lifetimes.rs | 9 +- .../literal_string_with_formatting_args.rs | 167 +++++ clippy_lints/src/manual_async_fn.rs | 21 +- clippy_lints/src/manual_float_methods.rs | 6 +- clippy_lints/src/manual_is_power_of_two.rs | 16 +- clippy_lints/src/matches/match_same_arms.rs | 20 +- clippy_lints/src/matches/mod.rs | 27 +- clippy_lints/src/matches/needless_match.rs | 6 +- clippy_lints/src/matches/single_match.rs | 2 +- .../src/methods/filter_map_identity.rs | 10 + .../map_with_unused_argument_over_ranges.rs | 2 +- clippy_lints/src/methods/mod.rs | 11 +- .../src/methods/needless_option_take.rs | 55 +- clippy_lints/src/methods/str_splitn.rs | 22 +- .../src/methods/unnecessary_iter_cloned.rs | 16 +- .../src/methods/unnecessary_sort_by.rs | 8 +- .../src/missing_const_for_thread_local.rs | 2 - clippy_lints/src/no_effect.rs | 2 +- .../src/operators/numeric_arithmetic.rs | 4 +- clippy_lints/src/precedence.rs | 33 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 3 +- clippy_lints/src/shadow.rs | 58 +- .../src/significant_drop_tightening.rs | 12 +- clippy_lints/src/single_range_in_vec_init.rs | 3 +- clippy_lints/src/strings.rs | 4 - clippy_lints/src/unit_types/let_unit_value.rs | 35 +- clippy_lints/src/unit_types/unit_arg.rs | 4 +- clippy_lints/src/unnecessary_literal_bound.rs | 2 +- .../src/unnecessary_struct_initialization.rs | 6 +- clippy_lints/src/useless_conversion.rs | 55 +- clippy_lints/src/utils/author.rs | 6 +- .../almost_standard_lint_formulation.rs | 5 +- .../interning_defined_symbol.rs | 2 +- .../internal_lints/lint_without_lint_pass.rs | 10 +- .../internal_lints/slow_symbol_comparisons.rs | 17 +- clippy_lints/src/zombie_processes.rs | 275 +++++--- clippy_utils/README.md | 2 +- .../src/{ast_utils.rs => ast_utils/mod.rs} | 0 clippy_utils/src/attrs.rs | 6 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/hir_utils.rs | 22 +- clippy_utils/src/lib.rs | 67 +- clippy_utils/src/msrvs.rs | 9 +- clippy_utils/src/paths.rs | 1 - clippy_utils/src/{ty.rs => ty/mod.rs} | 2 +- clippy_utils/src/visitors.rs | 2 +- lintcheck/src/main.rs | 3 +- rust-toolchain | 2 +- src/driver.rs | 4 +- .../interning_defined_symbol.fixed | 2 +- .../interning_defined_symbol.stderr | 2 +- .../ui-internal/unnecessary_symbol_str.fixed | 4 +- .../ui-internal/unnecessary_symbol_str.stderr | 4 +- tests/ui-toml/indexing_slicing/clippy.toml | 1 + .../indexing_slicing/indexing_slicing.rs | 19 + .../indexing_slicing/indexing_slicing.stderr | 12 + .../large_include_file/large_include_file.rs | 1 + .../large_include_file.stderr | 6 +- .../index_refutable_slice.fixed | 24 + .../index_refutable_slice.rs | 2 - .../index_refutable_slice.stderr | 14 +- .../toml_unknown_key/conf_unknown_key.stderr | 3 + tests/ui/as_pointer_underscore.fixed | 15 + tests/ui/as_pointer_underscore.rs | 15 + tests/ui/as_pointer_underscore.stderr | 17 + tests/ui/auxiliary/proc_macro_derive.rs | 1 + tests/ui/borrow_and_ref_as_ptr.fixed | 11 + tests/ui/borrow_and_ref_as_ptr.rs | 11 + tests/ui/borrow_and_ref_as_ptr.stderr | 17 + tests/ui/borrow_as_ptr_raw_ref.fixed | 19 + tests/ui/borrow_as_ptr_raw_ref.rs | 19 + tests/ui/borrow_as_ptr_raw_ref.stderr | 17 + tests/ui/comparison_chain.rs | 13 + tests/ui/comparison_chain.stderr | 53 +- tests/ui/default_union_representation.rs | 1 + tests/ui/default_union_representation.stderr | 8 +- tests/ui/derive.rs | 1 + tests/ui/derive.stderr | 20 +- tests/ui/doc/doc_lazy_list.fixed | 6 + tests/ui/doc/doc_lazy_list.rs | 6 + .../ui/doc/doc_nested_refdef_blockquote.fixed | 133 ++++ tests/ui/doc/doc_nested_refdef_blockquote.rs | 133 ++++ .../doc/doc_nested_refdef_blockquote.stderr | 148 +++++ .../ui/doc/doc_nested_refdef_list_item.fixed | 71 +++ tests/ui/doc/doc_nested_refdef_list_item.rs | 71 +++ .../ui/doc/doc_nested_refdef_list_item.stderr | 148 +++++ tests/ui/filter_map_identity.fixed | 5 + tests/ui/filter_map_identity.rs | 5 + tests/ui/format.fixed | 3 +- tests/ui/format.rs | 3 +- tests/ui/format.stderr | 30 +- tests/ui/if_not_else.fixed | 73 +++ tests/ui/if_not_else.rs | 42 ++ tests/ui/if_not_else.stderr | 116 +++- .../if_let_slice_binding.fixed | 177 ++++++ .../if_let_slice_binding.rs | 2 - .../if_let_slice_binding.stderr | 122 ++-- .../slice_indexing_in_macro.fixed | 29 + .../slice_indexing_in_macro.rs | 2 - .../slice_indexing_in_macro.stderr | 13 +- tests/ui/let_unit.fixed | 196 ++++++ tests/ui/let_unit.rs | 2 - tests/ui/let_unit.stderr | 22 +- .../ui/literal_string_with_formatting_arg.rs | 37 ++ .../literal_string_with_formatting_arg.stderr | 71 +++ tests/ui/manual_async_fn.fixed | 116 ++++ tests/ui/manual_async_fn.rs | 3 +- tests/ui/manual_async_fn.stderr | 134 ++-- tests/ui/manual_split_once.fixed | 144 +++++ tests/ui/manual_split_once.rs | 2 - tests/ui/manual_split_once.stderr | 108 ++-- tests/ui/match_same_arms.stderr | 63 +- tests/ui/match_same_arms2.fixed | 259 ++++++++ tests/ui/match_same_arms2.rs | 2 - tests/ui/match_same_arms2.stderr | 141 ++--- tests/ui/must_use_unit.fixed | 6 + tests/ui/must_use_unit.rs | 6 + tests/ui/must_use_unit.stderr | 18 +- tests/ui/needless_lifetimes.fixed | 14 + tests/ui/needless_lifetimes.rs | 14 + tests/ui/needless_match.fixed | 53 ++ tests/ui/needless_match.rs | 61 ++ tests/ui/needless_match.stderr | 14 +- tests/ui/needless_option_take.fixed | 13 - tests/ui/needless_option_take.rs | 47 +- tests/ui/needless_option_take.stderr | 71 ++- tests/ui/precedence.fixed | 4 + tests/ui/precedence.rs | 4 + tests/ui/precedence.stderr | 26 +- tests/ui/print_literal.fixed | 2 +- tests/ui/print_literal.rs | 2 +- tests/ui/rename.fixed | 1 + tests/ui/rename.rs | 1 + tests/ui/rename.stderr | 134 ++-- tests/ui/repr_packed_without_abi.rs | 37 ++ tests/ui/repr_packed_without_abi.stderr | 35 ++ tests/ui/result_unit_error_no_std.rs | 26 + tests/ui/result_unit_error_no_std.stderr | 12 + tests/ui/shadow.rs | 22 + tests/ui/shadow.stderr | 38 +- tests/ui/significant_drop_tightening.fixed | 144 +++++ tests/ui/significant_drop_tightening.rs | 2 - tests/ui/significant_drop_tightening.stderr | 18 +- tests/ui/single_match.fixed | 34 +- tests/ui/single_match.rs | 27 + tests/ui/single_match.stderr | 32 +- tests/ui/trailing_empty_array.rs | 1 + tests/ui/trailing_empty_array.stderr | 22 +- ...nlined_format_args_panic.edition2018.fixed | 1 + ...lined_format_args_panic.edition2018.stderr | 2 +- ...nlined_format_args_panic.edition2021.fixed | 1 + ...lined_format_args_panic.edition2021.stderr | 12 +- tests/ui/uninlined_format_args_panic.rs | 1 + tests/ui/unnecessary_iter_cloned.fixed | 201 ++++++ tests/ui/unnecessary_iter_cloned.rs | 2 - tests/ui/unnecessary_iter_cloned.stderr | 43 +- tests/ui/unnecessary_sort_by_no_std.fixed | 20 + tests/ui/unnecessary_sort_by_no_std.rs | 20 + tests/ui/unnecessary_sort_by_no_std.stderr | 17 + tests/ui/unnecessary_to_owned.fixed | 587 ++++++++++++++++++ tests/ui/unnecessary_to_owned.rs | 2 - tests/ui/unnecessary_to_owned.stderr | 194 +++--- tests/ui/useless_attribute.fixed | 9 + tests/ui/useless_attribute.rs | 9 + tests/ui/useless_conversion.fixed | 45 ++ tests/ui/useless_conversion.rs | 45 ++ tests/ui/useless_conversion.stderr | 124 ++-- tests/ui/zombie_processes.rs | 41 +- tests/ui/zombie_processes.stderr | 85 ++- util/gh-pages/script.js | 14 +- 208 files changed, 6002 insertions(+), 1415 deletions(-) create mode 100644 clippy_lints/src/attrs/repr_attributes.rs create mode 100644 clippy_lints/src/casts/as_pointer_underscore.rs create mode 100644 clippy_lints/src/literal_string_with_formatting_args.rs rename clippy_utils/src/{ast_utils.rs => ast_utils/mod.rs} (100%) rename clippy_utils/src/{ty.rs => ty/mod.rs} (99%) create mode 100644 tests/ui-toml/indexing_slicing/clippy.toml create mode 100644 tests/ui-toml/indexing_slicing/indexing_slicing.rs create mode 100644 tests/ui-toml/indexing_slicing/indexing_slicing.stderr create mode 100644 tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed create mode 100644 tests/ui/as_pointer_underscore.fixed create mode 100644 tests/ui/as_pointer_underscore.rs create mode 100644 tests/ui/as_pointer_underscore.stderr create mode 100644 tests/ui/borrow_and_ref_as_ptr.fixed create mode 100644 tests/ui/borrow_and_ref_as_ptr.rs create mode 100644 tests/ui/borrow_and_ref_as_ptr.stderr create mode 100644 tests/ui/borrow_as_ptr_raw_ref.fixed create mode 100644 tests/ui/borrow_as_ptr_raw_ref.rs create mode 100644 tests/ui/borrow_as_ptr_raw_ref.stderr create mode 100644 tests/ui/doc/doc_nested_refdef_blockquote.fixed create mode 100644 tests/ui/doc/doc_nested_refdef_blockquote.rs create mode 100644 tests/ui/doc/doc_nested_refdef_blockquote.stderr create mode 100644 tests/ui/doc/doc_nested_refdef_list_item.fixed create mode 100644 tests/ui/doc/doc_nested_refdef_list_item.rs create mode 100644 tests/ui/doc/doc_nested_refdef_list_item.stderr create mode 100644 tests/ui/if_not_else.fixed create mode 100644 tests/ui/index_refutable_slice/if_let_slice_binding.fixed create mode 100644 tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed create mode 100644 tests/ui/let_unit.fixed create mode 100644 tests/ui/literal_string_with_formatting_arg.rs create mode 100644 tests/ui/literal_string_with_formatting_arg.stderr create mode 100644 tests/ui/manual_async_fn.fixed create mode 100644 tests/ui/manual_split_once.fixed create mode 100644 tests/ui/match_same_arms2.fixed delete mode 100644 tests/ui/needless_option_take.fixed create mode 100644 tests/ui/repr_packed_without_abi.rs create mode 100644 tests/ui/repr_packed_without_abi.stderr create mode 100644 tests/ui/result_unit_error_no_std.rs create mode 100644 tests/ui/result_unit_error_no_std.stderr create mode 100644 tests/ui/significant_drop_tightening.fixed create mode 100644 tests/ui/unnecessary_iter_cloned.fixed create mode 100644 tests/ui/unnecessary_sort_by_no_std.fixed create mode 100644 tests/ui/unnecessary_sort_by_no_std.rs create mode 100644 tests/ui/unnecessary_sort_by_no_std.stderr create mode 100644 tests/ui/unnecessary_to_owned.fixed diff --git a/CHANGELOG.md b/CHANGELOG.md index 61efaa3bf3e6d..b6033de935012 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5380,6 +5380,7 @@ Released 2018-09-13 [`arc_with_non_send_sync`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_with_non_send_sync [`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions +[`as_pointer_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_pointer_underscore [`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants @@ -5490,6 +5491,7 @@ Released 2018-09-13 [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown +[`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg @@ -5685,6 +5687,7 @@ Released 2018-09-13 [`lines_filter_map_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`lint_groups_priority`]: https://rust-lang.github.io/rust-clippy/master/index.html#lint_groups_priority +[`literal_string_with_formatting_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#literal_string_with_formatting_args [`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal @@ -5966,6 +5969,7 @@ Released 2018-09-13 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts +[`repr_packed_without_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi [`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used @@ -6210,6 +6214,7 @@ Released 2018-09-13 [`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero [`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests +[`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings [`allow-panic-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-tests diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 77910917963ee..c354e8914f5db 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -37,7 +37,7 @@ impl LateLintPass<'_> for MyStructLint { // Get type of `expr` let ty = cx.typeck_results().expr_ty(expr); // Match its kind to enter its type - match ty.kind { + match ty.kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), _ => () } diff --git a/book/src/development/infrastructure/backport.md b/book/src/development/infrastructure/backport.md index 6920c4e465619..9526d8af1c9dc 100644 --- a/book/src/development/infrastructure/backport.md +++ b/book/src/development/infrastructure/backport.md @@ -5,68 +5,108 @@ Backports in Clippy are rare and should be approved by the Clippy team. For example, a backport is done, if a crucial ICE was fixed or a lint is broken to a point, that it has to be disabled, before landing on stable. -Backports are done to the `beta` branch of Clippy. Backports to stable Clippy -releases basically don't exist, since this would require a Rust point release, -which is almost never justifiable for a Clippy fix. +> Note: If you think a PR should be backported you can label it with +> `beta-nominated`. This has to be done before the Thursday the week before the +> release. +## Filtering PRs to backport -## Backport the changes +First, find all labeled PRs using [this filter][beta-accepted-prs]. + +Next, look at each PR individually. There are a few things to check. Those need +some explanation and are quite subjective. Good judgement is required. + +1. **Is the fix worth a backport?** + + This is really subjective. An ICE fix usually is. Moving a lint to a _lower_ + group (from warn- to allow-by-default) usually as well. An FP fix usually not + (on its own). If a backport is done anyway, FP fixes might also be included. + If the PR has a lot of changes, backports must be considered more carefully. + +2. **Is the problem that was fixed by the PR already in `beta`?** + + It could be that the problem that was fixed by the PR hasn't made it to the + `beta` branch of the Rust repo yet. If that's the case, and the fix is + already synced to the Rust repo, the fix doesn't need to be backported, as it + will hit stable together with the commit that introduced the problem. If the + fix PR is not synced yet, the fix PR either needs to be "backported" to the + Rust `master` branch or to `beta` in the next backport cycle. + +3. **Make sure that the fix is on `master` before porting to `beta`** + + The fix must already be synced to the Rust `master` branch. Otherwise, the + next `beta` will be missing this fix again. If it is not yet in `master` it + should probably not be backported. If the backport is really important, do an + out-of-cycle sync first. However, the out-of-cycle sync should be small, + because the changes in that sync will get right into `beta`, without being + tested in `nightly` first. + +[beta-accepted-prs]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-nominated + +## Preparation + +> Note: All commands in this chapter will be run in the Rust clone. + +Follow the instructions in [defining remotes] to define the `clippy-upstream` +remote in the Rust repository. -Backports are done on the beta branch of the Clippy repository. +After that, fetch the remote with ```bash -# Assuming the current directory corresponds to the Clippy repository -$ git checkout beta -$ git checkout -b backport -$ git cherry-pick # `` is the commit hash of the commit(s), that should be backported -$ git push origin backport +git fetch clippy-upstream master ``` -Now you should test that the backport passes all the tests in the Rust -repository. You can do this with: +Then, switch to the `beta` branch: ```bash -# Assuming the current directory corresponds to the Rust repository -$ git checkout beta -# Make sure to change `your-github-name` to your github name in the following command -$ git subtree pull -p src/tools/clippy https://github.com//rust-clippy backport -$ ./x.py test src/tools/clippy +git switch beta +git fetch upstream +git reset --hard upstream/beta ``` -Should the test fail, you can fix Clippy directly in the Rust repository. This -has to be first applied to the Clippy beta branch and then again synced to the -Rust repository, though. The easiest way to do this is: +[defining remotes]: release.md#defining-remotes + +## Backport the changes + +When a PR is merged with the GitHub merge queue, the PR is closed with the message + +> \ (#\) + +This commit needs to be backported. To do that, find the `` of that commit +and run the following command in the clone of the **Rust repository**: ```bash -# In the Rust repository -$ git diff --patch --relative=src/tools/clippy > clippy.patch -# In the Clippy repository -$ git apply /path/to/clippy.patch -$ git add -u -$ git commit -m "Fix rustup fallout" -$ git push origin backport +git cherry-pick -m 1 `` ``` -After this, you can open a PR to the `beta` branch of the Clippy repository. +Do this for all PRs that should be backported. +## Open PR in the Rust repository -## Update Clippy in the Rust Repository +Next, open the PR for the backport. Make sure, the PR is opened towards the +`beta` branch and not the `master` branch. The PR description should look like +this: -This step must be done, **after** the PR of the previous step was merged. +``` +[beta] Clippy backports -After the backport landed in the Clippy repository, the branch has to be synced -back to the beta branch of the Rust repository. +r? @Mark-Simulacrum -```bash -# Assuming the current directory corresponds to the Rust repository -$ git checkout beta -$ git checkout -b clippy_backport -$ git subtree pull -p src/tools/clippy https://github.com/rust-lang/rust-clippy beta -$ git push origin clippy_backport +Backports: +- +- ... + + ``` -Make sure to test the backport in the Rust repository before opening a PR. This -is done with `./x.py test src/tools/clippy`. If that passes all tests, open a PR -to the `beta` branch of the Rust repository. In this PR you should tag the -Clippy team member, that agreed to the backport or the `@rust-lang/clippy` team. -Make sure to add `[beta]` to the title of the PR. +Mark is from the release team and they ultimately have to merge the PR before +branching a new `beta` version. Tag them to take care of the backport. Next, +list all the backports and give a short summary what's backported and why it is +worth backporting this. + +## Relabel backported PRs + +When a PR is backported to Rust `beta`, label the PR with `beta-accepted`. This +will then get picked up when [writing the changelog]. + +[writing the changelog]: changelog_update.md#31-include-beta-accepted-prs diff --git a/book/src/development/infrastructure/release.md b/book/src/development/infrastructure/release.md index 98fabf8e89aee..20b870eb69a8e 100644 --- a/book/src/development/infrastructure/release.md +++ b/book/src/development/infrastructure/release.md @@ -7,112 +7,114 @@ Clippy is released together with stable Rust releases. The dates for these releases can be found at the [Rust Forge]. This document explains the necessary steps to create a Clippy release. -1. [Remerge the `beta` branch](#remerge-the-beta-branch) -2. [Update the `beta` branch](#update-the-beta-branch) -3. [Find the Clippy commit](#find-the-clippy-commit) -4. [Tag the stable commit](#tag-the-stable-commit) -5. [Update `CHANGELOG.md`](#update-changelogmd) - -> _NOTE:_ This document is for stable Rust releases, not for point releases. For -> point releases, step 1. and 2. should be enough. +1. [Defining Remotes](#defining-remotes) +1. [Bump Version](#bump-version) +1. [Find the Clippy commit](#find-the-clippy-commit) +1. [Update the `beta` branch](#update-the-beta-branch) +1. [Update the `stable` branch](#update-the-stable-branch) +1. [Tag the stable commit](#tag-the-stable-commit) +1. [Update `CHANGELOG.md`](#update-changelogmd) [Rust Forge]: https://forge.rust-lang.org/ -## Remerge the `beta` branch +## Defining Remotes + +You may want to define the `upstream` remote of the Clippy project to simplify +the following steps. However, this is optional and you can replace `upstream` +with the full URL instead. + +```bash +git remote add upstream git@github.com:rust-lang/rust-clippy +``` -This step is only necessary, if since the last release something was backported -to the beta Rust release. The remerge is then necessary, to make sure that the -Clippy commit, that was used by the now stable Rust release, persists in the -tree of the Clippy repository. +## Bump Version -To find out if this step is necessary run +When a release needs to be done, `cargo test` will fail, if the versions in the +`Cargo.toml` are not correct. During that sync, the versions need to be bumped. +This is done by running: ```bash -# Assumes that the local master branch of rust-lang/rust-clippy is up-to-date -$ git fetch upstream -$ git branch master --contains upstream/beta +cargo dev release bump_version ``` -If this command outputs `master`, this step is **not** necessary. +This will increase the version number of each relevant `Cargo.toml` file. After +that, just commit the updated files with: ```bash -# Assuming `HEAD` is the current `master` branch of rust-lang/rust-clippy -$ git checkout -b backport_remerge -$ git merge upstream/beta -$ git diff # This diff has to be empty, otherwise something with the remerge failed -$ git push origin backport_remerge # This can be pushed to your fork +git commit -m "Bump Clippy version -> 0.1.XY" **/*Cargo.toml ``` -After this, open a PR to the master branch. In this PR, the commit hash of the -`HEAD` of the `beta` branch must exist. In addition to that, no files should be -changed by this PR. +`XY` should be exchanged with the corresponding version -## Update the `beta` branch +## Find the Clippy commit -This step must be done **after** the PR of the previous step was merged. +For both updating the `beta` and the `stable` branch, the first step is to find +the Clippy commit of the last Clippy sync done in the respective Rust branch. -First, the Clippy commit of the `beta` branch of the Rust repository has to be -determined. +Running the following commands _in the Rust repo_ will get the commit for the +specified ``: ```bash -# Assuming the current directory corresponds to the Rust repository -$ git fetch upstream -$ git checkout upstream/beta -$ BETA_SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g") +git switch +SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g") ``` -After finding the Clippy commit, the `beta` branch in the Clippy repository can -be updated. +Where `` is one of `stable`, `beta`, or `master`. + +## Update the `beta` branch + +After getting the commit of the `beta` branch, the `beta` branch in the Clippy +repository can be updated. ```bash -# Assuming the current directory corresponds to the Clippy repository -$ git checkout beta -$ git reset --hard $BETA_SHA -$ git push upstream beta +git checkout beta +git reset --hard $SHA +git push upstream beta ``` -## Find the Clippy commit +## Update the `stable` branch -The first step is to tag the Clippy commit, that is included in the stable Rust -release. This commit can be found in the Rust repository. +After getting the commit of the `stable` branch, the `stable` branch in the +Clippy repository can be updated. ```bash -# Assuming the current directory corresponds to the Rust repository -$ git fetch upstream # `upstream` is the `rust-lang/rust` remote -$ git checkout 1.XX.0 # XX should be exchanged with the corresponding version -$ SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g") +git checkout stable +git reset --hard $SHA +git push upstream stable ``` -## Tag the stable commit +## Tag the `stable` commit -After finding the Clippy commit, it can be tagged with the release number. +After updating the `stable` branch, tag the HEAD commit and push it to the +Clippy repo. + +> Note: Only push the tag once the Deploy GitHub action of the `beta` branch is +> finished. Otherwise the deploy for the tag might fail. ```bash -# Assuming the current directory corresponds to the Clippy repository -$ git checkout $SHA -$ git tag rust-1.XX.0 # XX should be exchanged with the corresponding version -$ git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote +git tag rust-1.XX.0 # XX should be exchanged with the corresponding version +git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote ``` After this, the release should be available on the Clippy [release page]. [release page]: https://github.com/rust-lang/rust-clippy/releases -## Update the `stable` branch +## Publish `clippy_utils` + +The `clippy_utils` crate is published to `crates.io` without any stability +guarantees. To do this, after the [sync] and the release is done, switch back to +the `upstream/master` branch and publish `clippy_utils`: -At this step you should have already checked out the commit of the `rust-1.XX.0` -tag. Updating the stable branch from here is as easy as: +> Note: The Rustup PR bumping the nightly and Clippy version **must** be merged +> before doing this. ```bash -# Assuming the current directory corresponds to the Clippy repository and the -# commit of the just created rust-1.XX.0 tag is checked out. -$ git push upstream rust-1.XX.0:stable # `upstream` is the `rust-lang/rust-clippy` remote +git switch master && git pull upstream master +cargo publish --manifest-path clippy_utils/Cargo.toml ``` -> _NOTE:_ Usually there are no stable backports for Clippy, so this update -> should be possible without force pushing or anything like this. If there -> should have happened a stable backport, make sure to re-merge those changes -> just as with the `beta` branch. +[sync]: sync.md ## Update `CHANGELOG.md` diff --git a/book/src/development/infrastructure/sync.md b/book/src/development/infrastructure/sync.md index e1fe92f95250d..da1ad586607f9 100644 --- a/book/src/development/infrastructure/sync.md +++ b/book/src/development/infrastructure/sync.md @@ -21,6 +21,8 @@ to beta. For reference, the first sync following this cadence was performed the This process is described in detail in the following sections. For general information about `subtree`s in the Rust repository see [the rustc-dev-guide][subtree]. +[subtree]: https://rustc-dev-guide.rust-lang.org/external-repos.html#external-dependencies-subtree + ## Patching git-subtree to work with big repos Currently, there's a bug in `git-subtree` that prevents it from working properly @@ -50,23 +52,11 @@ sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subt > `bash` instead. You can do this by editing the first line of the `git-subtree` > script and changing `sh` to `bash`. -## Defining remotes - -You may want to define remotes, so you don't have to type out the remote -addresses on every sync. You can do this with the following commands (these -commands still have to be run inside the `rust` directory): - -```bash -# Set clippy-upstream remote for pulls -$ git remote add clippy-upstream https://github.com/rust-lang/rust-clippy -# Make sure to not push to the upstream repo -$ git remote set-url --push clippy-upstream DISABLED -# Set a local remote -$ git remote add clippy-local /path/to/rust-clippy -``` +> Note: The following sections assume that you have set up remotes following the +> instructions in [defining remotes]. -> Note: The following sections assume that you have set those remotes with the -> above remote names. +[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 +[defining remotes]: release.md#defining-remotes ## Performing the sync from [`rust-lang/rust`] to Clippy @@ -78,9 +68,9 @@ to be run inside the `rust` directory): `rustup check`. 3. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash - # Be sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand + # Be sure to either use a net-new branch, e.g. `rustup`, or delete the branch beforehand # because changes cannot be fast forwarded and you have to run this command again. - git subtree push -P src/tools/clippy clippy-local sync-from-rust + git subtree push -P src/tools/clippy clippy-local rustup ``` > _Note:_ Most of the time you have to create a merge commit in the @@ -88,21 +78,22 @@ to be run inside the `rust` directory): > rust-copy of Clippy): ```bash git fetch upstream # assuming upstream is the rust-lang/rust remote - git checkout sync-from-rust + git switch rustup git merge upstream/master --no-ff ``` > Note: This is one of the few instances where a merge commit is allowed in > a PR. -4. Bump the nightly version in the Clippy repository by changing the date in the - rust-toolchain file to the current date and committing it with the message: +4. Bump the nightly version in the Clippy repository by running these commands: ```bash - git commit -m "Bump nightly version -> YYYY-MM-DD" + cargo dev sync update_nightly + git commit -m "Bump nightly version -> YYYY-MM-DD" rust-toolchain clippy_utils/README.md ``` 5. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or ask them in the [Zulip] stream.) [Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy +[`rust-lang/rust`]: https://github.com/rust-lang/rust ## Performing the sync from Clippy to [`rust-lang/rust`] @@ -111,11 +102,7 @@ All the following commands have to be run inside the `rust` directory. 1. Make sure you have checked out the latest `master` of `rust-lang/rust`. 2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: ```bash - git checkout -b sync-from-clippy + git switch -c clippy-subtree-update git subtree pull -P src/tools/clippy clippy-upstream master ``` 3. Open a PR to [`rust-lang/rust`] - -[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 -[subtree]: https://rustc-dev-guide.rust-lang.org/external-repos.html#external-dependencies-subtree -[`rust-lang/rust`]: https://github.com/rust-lang/rust diff --git a/book/src/development/the_team.md b/book/src/development/the_team.md index 10341791cec4b..6bc0783b166a9 100644 --- a/book/src/development/the_team.md +++ b/book/src/development/the_team.md @@ -72,7 +72,7 @@ you to the alumni group. You're always welcome to come back. ## The Clippy Team -[The Clippy team](https://www.rust-lang.org/governance/teams/dev-tools#Clippy%20team) +[The Clippy team](https://www.rust-lang.org/governance/teams/dev-tools#team-clippy) is responsible for maintaining Clippy. ### Duties diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index e6da4322a1793..578836ecc5686 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -94,7 +94,7 @@ impl LateLintPass<'_> for MyStructLint { // Get type of `expr` let ty = cx.typeck_results().expr_ty(expr); // Match its kind to enter the type - match ty.kind { + match ty.kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), _ => () } diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 275d125096e95..ea1d7d11389d1 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -81,6 +81,16 @@ Whether `expect` should be allowed in test functions or `#[cfg(test)]` * [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) +## `allow-indexing-slicing-in-tests` +Whether `indexing_slicing` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) + + ## `allow-mixed-uninlined-format-args` Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 41b56b45d9aef..bffa04f6f090b 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -291,6 +291,9 @@ define_Conf! { /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` #[lints(expect_used)] allow_expect_in_tests: bool = false, + /// Whether `indexing_slicing` should be allowed in test functions or `#[cfg(test)]` + #[lints(indexing_slicing)] + allow_indexing_slicing_in_tests: bool = false, /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` #[lints(uninlined_format_args)] allow_mixed_uninlined_format_args: bool = true, diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs index 8719f61a89034..cf33e1444e47d 100644 --- a/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -126,7 +126,7 @@ declare_clippy_lint! { /// /// [cargo-pgo]: https://github.com/Kobzol/cargo-pgo/blob/main/README.md /// - #[clippy::version = "1.82.0"] + #[clippy::version = "1.84.0"] pub ARBITRARY_SOURCE_ITEM_ORDERING, restriction, "arbitrary source item ordering" diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index a9766597d50d7..92efd1a4ddcda 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -7,6 +7,7 @@ mod duplicated_attributes; mod inline_always; mod mixed_attributes_style; mod non_minimal_cfg; +mod repr_attributes; mod should_panic_without_expect; mod unnecessary_clippy_cfg; mod useless_attribute; @@ -272,6 +273,44 @@ declare_clippy_lint! { "ensures that all `should_panic` attributes specify its expected panic message" } +declare_clippy_lint! { + /// ### What it does + /// Checks for items with `#[repr(packed)]`-attribute without ABI qualification + /// + /// ### Why is this bad? + /// Without qualification, `repr(packed)` implies `repr(Rust)`. The Rust-ABI is inherently unstable. + /// While this is fine as long as the type is accessed correctly within Rust-code, most uses + /// of `#[repr(packed)]` involve FFI and/or data structures specified by network-protocols or + /// other external specifications. In such situations, the unstable Rust-ABI implied in + /// `#[repr(packed)]` may lead to future bugs should the Rust-ABI change. + /// + /// In case you are relying on a well defined and stable memory layout, qualify the type's + /// representation using the `C`-ABI. Otherwise, if the type in question is only ever + /// accessed from Rust-code according to Rust's rules, use the `Rust`-ABI explicitly. + /// + /// ### Example + /// ```no_run + /// #[repr(packed)] + /// struct NetworkPacketHeader { + /// header_length: u8, + /// header_version: u16 + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[repr(C, packed)] + /// struct NetworkPacketHeader { + /// header_length: u8, + /// header_version: u16 + /// } + /// ``` + #[clippy::version = "1.84.0"] + pub REPR_PACKED_WITHOUT_ABI, + suspicious, + "ensures that `repr(packed)` always comes with a qualified ABI" +} + declare_clippy_lint! { /// ### What it does /// Checks for `any` and `all` combinators in `cfg` with only one condition. @@ -415,6 +454,7 @@ pub struct Attributes { impl_lint_pass!(Attributes => [ INLINE_ALWAYS, + REPR_PACKED_WITHOUT_ABI, ]); impl Attributes { @@ -431,6 +471,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if is_relevant_item(cx, item) { inline_always::check(cx, item.span, item.ident.name, attrs); } + repr_attributes::check(cx, item.span, attrs, &self.msrv); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { diff --git a/clippy_lints/src/attrs/repr_attributes.rs b/clippy_lints/src/attrs/repr_attributes.rs new file mode 100644 index 0000000000000..6d1ab46aa0c1f --- /dev/null +++ b/clippy_lints/src/attrs/repr_attributes.rs @@ -0,0 +1,43 @@ +use rustc_hir::Attribute; +use rustc_lint::LateContext; +use rustc_span::{Span, sym}; + +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs; + +use super::REPR_PACKED_WITHOUT_ABI; + +pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: &msrvs::Msrv) { + if msrv.meets(msrvs::REPR_RUST) { + check_packed(cx, item_span, attrs); + } +} + +fn check_packed(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { + if let Some(items) = attrs.iter().find_map(|attr| { + if attr.ident().is_some_and(|ident| matches!(ident.name, sym::repr)) { + attr.meta_item_list() + } else { + None + } + }) && let Some(packed) = items + .iter() + .find(|item| item.ident().is_some_and(|ident| matches!(ident.name, sym::packed))) + && !items.iter().any(|item| { + item.ident() + .is_some_and(|ident| matches!(ident.name, sym::C | sym::Rust)) + }) + { + span_lint_and_then( + cx, + REPR_PACKED_WITHOUT_ABI, + item_span, + "item uses `packed` representation without ABI-qualification", + |diag| { + diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI") + .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`") + .span_label(packed.span(), "`packed` representation set here"); + }, + ); + } +} diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index e21853598c3b5..e7158a6a6b6c7 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,8 +1,8 @@ use super::USELESS_ATTRIBUTE; -use super::utils::{extract_clippy_lint, is_lint_level, is_word}; +use super::utils::{is_lint_level, is_word, namespace_and_lint}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; -use rustc_ast::{Attribute, Item, ItemKind, MetaItemInner}; +use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; @@ -20,11 +20,13 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { for lint in lint_list { match item.kind { ItemKind::Use(..) => { - if let MetaItemInner::MetaItem(meta_item) = lint - && meta_item.is_word() - && let Some(ident) = meta_item.ident() + let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else { + return; + }; + + if namespace.is_none() && matches!( - ident.name.as_str(), + name.as_str(), "ambiguous_glob_reexports" | "dead_code" | "deprecated" @@ -39,9 +41,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } - if extract_clippy_lint(lint).is_some_and(|symbol| { - matches!( - symbol.as_str(), + if namespace == Some(sym::clippy) + && matches!( + name.as_str(), "wildcard_imports" | "enum_glob_use" | "redundant_pub_crate" @@ -52,7 +54,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { | "disallowed_types" | "unused_trait_names" ) - }) { + { return; } }, diff --git a/clippy_lints/src/attrs/utils.rs b/clippy_lints/src/attrs/utils.rs index 3bb02688bf22c..96de064290400 100644 --- a/clippy_lints/src/attrs/utils.rs +++ b/clippy_lints/src/attrs/utils.rs @@ -75,13 +75,18 @@ fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_> /// Returns the lint name if it is clippy lint. pub(super) fn extract_clippy_lint(lint: &MetaItemInner) -> Option { - if let Some(meta_item) = lint.meta_item() - && meta_item.path.segments.len() > 1 - && let tool_name = meta_item.path.segments[0].ident - && tool_name.name == sym::clippy - { - let lint_name = meta_item.path.segments.last().unwrap().ident.name; - return Some(lint_name); + match namespace_and_lint(lint) { + (Some(sym::clippy), name) => name, + _ => None, + } +} + +/// Returns the lint namespace, if any, as well as the lint name. (`None`, `None`) means +/// the lint had less than 1 or more than 2 segments. +pub(super) fn namespace_and_lint(lint: &MetaItemInner) -> (Option, Option) { + match lint.meta_item().map(|m| m.path.segments.as_slice()).unwrap_or_default() { + [name] => (None, Some(name.ident.name)), + [namespace, name] => (Some(namespace.ident.name), Some(name.ident.name)), + _ => (None, None), } - None } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index f68a7a89b3994..f8c30d1c881d0 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -5,11 +5,11 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; +use rustc_attr_parsing::RustcVersion; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; -use rustc_attr_parsing::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; diff --git a/clippy_lints/src/casts/as_pointer_underscore.rs b/clippy_lints/src/casts/as_pointer_underscore.rs new file mode 100644 index 0000000000000..536126fd02b3a --- /dev/null +++ b/clippy_lints/src/casts/as_pointer_underscore.rs @@ -0,0 +1,19 @@ +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; + +pub fn check<'tcx>(cx: &LateContext<'tcx>, ty_into: Ty<'_>, cast_to_hir: &'tcx rustc_hir::Ty<'tcx>) { + if let rustc_hir::TyKind::Ptr(rustc_hir::MutTy { ty, .. }) = cast_to_hir.kind + && matches!(ty.kind, rustc_hir::TyKind::Infer) + { + clippy_utils::diagnostics::span_lint_and_sugg( + cx, + super::AS_POINTER_UNDERSCORE, + cast_to_hir.span, + "using inferred pointer cast", + "use explicit type", + ty_into.to_string(), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index 4dd51dcbc9a20..67aa33ca06c31 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_context; -use clippy_utils::std_or_core; +use clippy_utils::{is_lint_allowed, msrvs, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -13,15 +14,12 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'_>, cast_expr: &'tcx Expr<'_>, cast_to: &'tcx Ty<'_>, -) { + msrv: &Msrv, +) -> bool { if matches!(cast_to.kind, TyKind::Ptr(_)) && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind - && let Some(std_or_core) = std_or_core(cx) + && !is_lint_allowed(cx, BORROW_AS_PTR, expr.hir_id) { - let macro_name = match mutability { - Mutability::Not => "addr_of", - Mutability::Mut => "addr_of_mut", - }; let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; // Fix #9884 @@ -31,17 +29,36 @@ pub(super) fn check<'tcx>( .get(base.hir_id) .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) }) { - return; + return false; } + let suggestion = if msrv.meets(msrvs::RAW_REF_OP) { + let operator_kind = match mutability { + Mutability::Not => "const", + Mutability::Mut => "mut", + }; + format!("&raw {operator_kind} {snip}") + } else { + let Some(std_or_core) = std_or_core(cx) else { + return false; + }; + let macro_name = match mutability { + Mutability::Not => "addr_of", + Mutability::Mut => "addr_of_mut", + }; + format!("{std_or_core}::ptr::{macro_name}!({snip})") + }; + span_lint_and_sugg( cx, BORROW_AS_PTR, expr.span, "borrow as raw pointer", "try", - format!("{std_or_core}::ptr::{macro_name}!({snip})"), + suggestion, Applicability::MachineApplicable, ); + return true; } + false } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 8b884399f9234..c64c0e15144de 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,3 +1,4 @@ +mod as_pointer_underscore; mod as_ptr_cast_mut; mod as_underscore; mod borrow_as_ptr; @@ -574,13 +575,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for the usage of `&expr as *const T` or - /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or - /// `ptr::addr_of_mut` instead. + /// `&mut expr as *mut T`, and suggest using `&raw const` or + /// `&raw mut` instead. /// /// ### Why is this bad? /// This would improve readability and avoid creating a reference /// that points to an uninitialized value or unaligned place. - /// Read the `ptr::addr_of` docs for more information. + /// Read the `&raw` explanation in the Reference for more information. /// /// ### Example /// ```no_run @@ -593,10 +594,10 @@ declare_clippy_lint! { /// Use instead: /// ```no_run /// let val = 1; - /// let p = std::ptr::addr_of!(val); + /// let p = &raw const val; /// /// let mut val_mut = 1; - /// let p_mut = std::ptr::addr_of_mut!(val_mut); + /// let p_mut = &raw mut val_mut; /// ``` #[clippy::version = "1.60.0"] pub BORROW_AS_PTR, @@ -726,6 +727,33 @@ declare_clippy_lint! { "using `as` to cast a reference to pointer" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of `as *const _` or `as *mut _` conversion using inferred type. + /// + /// ### Why restrict this? + /// The conversion might include a dangerous cast that might go undetected due to the type being inferred. + /// + /// ### Example + /// ```no_run + /// fn as_usize(t: &T) -> usize { + /// // BUG: `t` is already a reference, so we will here + /// // return a dangling pointer to a temporary value instead + /// &t as *const _ as usize + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn as_usize(t: &T) -> usize { + /// t as *const T as usize + /// } + /// ``` + #[clippy::version = "1.81.0"] + pub AS_POINTER_UNDERSCORE, + restriction, + "detects `as *mut _` and `as *const _` conversion" +} + pub struct Casts { msrv: Msrv, } @@ -763,6 +791,7 @@ impl_lint_pass!(Casts => [ CAST_NAN_TO_INT, ZERO_PTR, REF_AS_PTR, + AS_POINTER_UNDERSCORE, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -805,11 +834,15 @@ impl<'tcx> LateLintPass<'tcx> for Casts { } as_underscore::check(cx, expr, cast_to_hir); - - if self.msrv.meets(msrvs::PTR_FROM_REF) { + as_pointer_underscore::check(cx, cast_to, cast_to_hir); + + let was_borrow_as_ptr_emitted = if self.msrv.meets(msrvs::BORROW_AS_PTR) { + borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv) + } else { + false + }; + if self.msrv.meets(msrvs::PTR_FROM_REF) && !was_borrow_as_ptr_emitted { ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); - } else if self.msrv.meets(msrvs::BORROW_AS_PTR) { - borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index c85e3500ebdc9..61c92d441d097 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,8 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{SpanlessEq, if_sequence, is_else_clause, is_in_const_context}; +use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -120,13 +122,19 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { return; } } - span_lint_and_help( + let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else { + unreachable!(); + }; + let lhs = Sugg::hir(cx, lhs, "..").maybe_par(); + let rhs = Sugg::hir(cx, rhs, "..").addr(); + span_lint_and_sugg( cx, COMPARISON_CHAIN, expr.span, "`if` chain can be rewritten with `match`", - None, - "consider rewriting the `if` chain to use `cmp` and `match`", + "consider rewriting the `if` chain with `match`", + format!("match {lhs}.cmp({rhs}) {{...}}"), + Applicability::HasPlaceholders, ); } } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 022ed180ed8ca..7451fb909ef84 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -55,6 +55,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, + crate::attrs::REPR_PACKED_WITHOUT_ABI_INFO, crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO, crate::attrs::UNNECESSARY_CLIPPY_CFG_INFO, crate::attrs::USELESS_ATTRIBUTE_INFO, @@ -75,6 +76,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::cargo::NEGATIVE_FEATURE_NAMES_INFO, crate::cargo::REDUNDANT_FEATURE_NAMES_INFO, crate::cargo::WILDCARD_DEPENDENCIES_INFO, + crate::casts::AS_POINTER_UNDERSCORE_INFO, crate::casts::AS_PTR_CAST_MUT_INFO, crate::casts::AS_UNDERSCORE_INFO, crate::casts::BORROW_AS_PTR_INFO, @@ -139,6 +141,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::doc::DOC_LAZY_CONTINUATION_INFO, crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, + crate::doc::DOC_NESTED_REFDEFS_INFO, crate::doc::EMPTY_DOCS_INFO, crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, @@ -277,6 +280,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::literal_representation::MISTYPED_LITERAL_SUFFIXES_INFO, crate::literal_representation::UNREADABLE_LITERAL_INFO, crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO, + crate::literal_string_with_formatting_args::LITERAL_STRING_WITH_FORMATTING_ARGS_INFO, crate::loops::EMPTY_LOOP_INFO, crate::loops::EXPLICIT_COUNTER_LOOP_INFO, crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO, diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 6819ad547f876..3b3a78cb11530 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -26,7 +26,8 @@ declare_clippy_lint! { /// 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. + /// This lint is implemented using a custom algorithm independent of rustc's inference, + /// which results in many false positives and false negatives. /// /// ### Example /// ```no_run @@ -36,8 +37,8 @@ declare_clippy_lint! { /// /// Use instead: /// ```no_run - /// let i = 10i32; - /// let f = 1.23f64; + /// let i = 10_i32; + /// let f = 1.23_f64; /// ``` #[clippy::version = "1.52.0"] pub DEFAULT_NUMERIC_FALLBACK, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 821312a9e401c..653726872c645 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1004,7 +1004,10 @@ fn report<'tcx>( let needs_paren = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { Node::Expr(e) => match e.kind { ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false, - ExprKind::Call(..) => expr.precedence() < ExprPrecedence::Unambiguous || matches!(expr.kind, ExprKind::Field(..)), + ExprKind::Call(..) => { + expr.precedence() < ExprPrecedence::Unambiguous + || matches!(expr.kind, ExprKind::Field(..)) + }, _ => expr.precedence() < e.precedence(), }, _ => false, @@ -1017,11 +1020,7 @@ fn report<'tcx>( }) ); - let sugg = if !snip_is_macro - && needs_paren - && !has_enclosing_paren(&snip) - && !is_in_tuple - { + let sugg = if !snip_is_macro && needs_paren && !has_enclosing_paren(&snip) && !is_in_tuple { format!("({snip})") } else { snip.into() diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index f65edd3625308..7c2f5efd8dd44 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -6,9 +6,7 @@ use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, pat use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item}; -use rustc_hir::{ - self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, -}; +use rustc_hir::{self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{ @@ -453,7 +451,7 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) && !has_non_exhaustive_attr(cx.tcx, *adt) && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id) - && let typing_env = typing_env_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && let typing_env = typing_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 @@ -484,7 +482,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De } /// Creates the `ParamEnv` used for the give type's derived `Eq` impl. -fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> { +fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> { // Initial map from generic index to param def. // Vec<(param_def, needs_eq)> let mut params = tcx diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index a0cb36f88dc05..a78c392e20866 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -43,7 +43,6 @@ declare_clippy_lint! { /// ```no_run /// use serde::Serialize; /// - /// // Example code where clippy issues a warning /// println!("warns"); /// /// // The diagnostic will contain the message "no serializing" diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 1e660b1957a44..c4ed118b7c9fc 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -35,7 +35,6 @@ declare_clippy_lint! { /// ``` /// /// ```rust,ignore - /// // Example code where clippy issues a warning /// let xs = vec![1, 2, 3, 4]; /// xs.leak(); // Vec::leak is disallowed in the config. /// // The diagnostic contains the message "no leaking memory". @@ -47,7 +46,6 @@ declare_clippy_lint! { /// /// Use instead: /// ```rust,ignore - /// // Example code which does not raise clippy warning /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` diff --git a/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/clippy_lints/src/doc/include_in_doc_without_cfg.rs index 0bb16a0c77d5c..4b40fc0b1ee2c 100644 --- a/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrStyle}; +use rustc_ast::AttrStyle; use rustc_errors::Applicability; +use rustc_hir::{AttrArgs, AttrKind, Attribute}; use rustc_lint::LateContext; -use rustc_hir::{Attribute, AttrKind, AttrArgs}; use super::DOC_INCLUDE_WITHOUT_CFG; diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index f65acd7978a74..b2135fe18bd9e 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -5,7 +5,7 @@ mod too_long_first_doc_paragraph; use clippy_config::Conf; use clippy_utils::attrs::is_doc_hidden; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; @@ -17,6 +17,7 @@ use pulldown_cmark::Event::{ use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -563,6 +564,32 @@ declare_clippy_lint! { "check if files included in documentation are behind `cfg(doc)`" } +declare_clippy_lint! { + /// ### What it does + /// Warns if a link reference definition appears at the start of a + /// list item or quote. + /// + /// ### Why is this bad? + /// This is probably intended as an intra-doc link. If it is really + /// supposed to be a reference definition, it can be written outside + /// of the list item or quote. + /// + /// ### Example + /// ```no_run + /// //! - [link]: description + /// ``` + /// Use instead: + /// ```no_run + /// //! - [link][]: description (for intra-doc link) + /// //! + /// //! [link]: destination (for link reference definition) + /// ``` + #[clippy::version = "1.84.0"] + pub DOC_NESTED_REFDEFS, + suspicious, + "link reference defined in list item or quote" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -580,6 +607,7 @@ impl Documentation { impl_lint_pass!(Documentation => [ DOC_LINK_WITH_QUOTES, DOC_MARKDOWN, + DOC_NESTED_REFDEFS, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, @@ -831,6 +859,31 @@ fn check_doc<'a, Events: Iterator, Range { blockquote_level += 1; containers.push(Container::Blockquote); + if let Some((next_event, next_range)) = events.peek() { + let next_start = match next_event { + End(TagEnd::BlockQuote) => next_range.end, + _ => next_range.start, + }; + if let Some(refdefrange) = looks_like_refdef(doc, range.start..next_start) && + let Some(refdefspan) = fragments.span(cx, refdefrange.clone()) + { + span_lint_and_then( + cx, + DOC_NESTED_REFDEFS, + refdefspan, + "link reference defined in quote", + |diag| { + diag.span_suggestion_short( + refdefspan.shrink_to_hi(), + "for an intra-doc link, add `[]` between the label and the colon", + "[]", + Applicability::MaybeIncorrect, + ); + diag.help("link definitions are not shown in rendered documentation"); + } + ); + } + } }, End(TagEnd::BlockQuote) => { blockquote_level -= 1; @@ -869,11 +922,42 @@ fn check_doc<'a, Events: Iterator, Range next_range.end, + _ => next_range.start, + }; + if let Some(refdefrange) = looks_like_refdef(doc, range.start..next_start) && + let Some(refdefspan) = fragments.span(cx, refdefrange.clone()) + { + span_lint_and_then( + cx, + DOC_NESTED_REFDEFS, + refdefspan, + "link reference defined in list item", + |diag| { + diag.span_suggestion_short( + refdefspan.shrink_to_hi(), + "for an intra-doc link, add `[]` between the label and the colon", + "[]", + Applicability::MaybeIncorrect, + ); + diag.help("link definitions are not shown in rendered documentation"); + } + ); + refdefrange.start - range.start + } else { + let mut start = next_range.start; + if start > 0 && doc.as_bytes().get(start - 1) == Some(&b'\\') { + // backslashes aren't in the event stream... + start -= 1; + } + start - range.start + } } else { - containers.push(Container::List(0)); - } + 0 + }; + containers.push(Container::List(indent)); } ticks_unbalanced = false; paragraph_range = range; @@ -1045,3 +1129,25 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { self.cx.tcx.hir() } } + +#[expect(clippy::range_plus_one)] // inclusive ranges aren't the same type +fn looks_like_refdef(doc: &str, range: Range) -> Option> { + let offset = range.start; + let mut iterator = doc.as_bytes()[range].iter().copied().enumerate(); + let mut start = None; + while let Some((i, byte)) = iterator.next() { + match byte { + b'\\' => { + iterator.next(); + }, + b'[' => { + start = Some(i + offset); + }, + b']' if let Some(start) = start => { + return Some(start..i + offset + 1); + }, + _ => {}, + } + } + None +} diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 0550c22761a56..a5a4e05b3a6d2 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { // match call to write_fmt && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind) && let ExprKind::Call(write_recv_path, []) = write_recv.kind - && write_fun.ident.name.as_str() == "write_fmt" + && write_fun.ident.name == sym::write_fmt && let Some(def_id) = path_def_id(cx, write_recv_path) { // match calls to std::io::stdout() / std::io::stderr () diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index be3d0f7ad6343..243eb5cbfd40a 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -10,6 +10,7 @@ mod too_many_lines; use clippy_config::Conf; use clippy_utils::def_path_def_ids; +use clippy_utils::msrvs::Msrv; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; @@ -455,6 +456,7 @@ pub struct Functions { /// A set of resolved `def_id` of traits that are configured to allow /// function params renaming. trait_ids: DefIdSet, + msrv: Msrv, } impl Functions { @@ -469,6 +471,7 @@ impl Functions { .iter() .flat_map(|p| def_path_def_ids(tcx, &p.split("::").collect::>())) .collect(), + msrv: conf.msrv.clone(), } } } @@ -518,12 +521,12 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { must_use::check_item(cx, item); - result::check_item(cx, item, self.large_error_threshold); + result::check_item(cx, item, self.large_error_threshold, &self.msrv); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); - result::check_impl_item(cx, item, self.large_error_threshold); + result::check_impl_item(cx, item, self.large_error_threshold, &self.msrv); impl_trait_in_params::check_impl_item(cx, item); renamed_function_params::check_impl_item(cx, item, &self.trait_ids); } @@ -532,8 +535,10 @@ impl<'tcx> LateLintPass<'tcx> for Functions { too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold); not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); - result::check_trait_item(cx, item, self.large_error_threshold); + result::check_trait_item(cx, item, self.large_error_threshold, &self.msrv); impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api); } + + extract_msrv_attr!(LateContext); } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 2b26285429af5..afdb5d5306a6b 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -28,7 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, @@ -50,7 +50,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( cx, @@ -73,7 +73,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); if attr.is_none() && is_public && !is_proc_macro(attrs) { @@ -91,6 +91,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr } } +#[allow(clippy::too_many_arguments)] fn check_needless_must_use( cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, @@ -98,21 +99,54 @@ fn check_needless_must_use( item_span: Span, fn_header_span: Span, attr: &Attribute, + attrs: &[Attribute], sig: &FnSig<'_>, ) { if in_external_macro(cx.sess(), item_span) { return; } if returns_unit(decl) { - span_lint_and_then( - cx, - MUST_USE_UNIT, - fn_header_span, - "this unit-returning function has a `#[must_use]` attribute", - |diag| { - diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable); - }, - ); + if attrs.len() == 1 { + span_lint_and_then( + cx, + MUST_USE_UNIT, + fn_header_span, + "this unit-returning function has a `#[must_use]` attribute", + |diag| { + diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable); + }, + ); + } else { + // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see + // issue #12320. + span_lint_and_then( + cx, + MUST_USE_UNIT, + fn_header_span, + "this unit-returning function has a `#[must_use]` attribute", + |diag| { + let mut attrs_without_must_use = attrs.to_vec(); + attrs_without_must_use.retain(|a| a.id != attr.id); + let sugg_str = attrs_without_must_use + .iter() + .map(|a| { + if a.value_str().is_none() { + return a.name_or_empty().to_string(); + } + format!("{} = \"{}\"", a.name_or_empty(), a.value_str().unwrap()) + }) + .collect::>() + .join(", "); + + diag.span_suggestion( + attrs[0].span.with_hi(attrs[attrs.len() - 1].span.hi()), + "change these attributes to", + sugg_str, + Applicability::MachineApplicable, + ); + }, + ); + } } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index d4eaa1663208c..674d78eaae76a 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -1,3 +1,4 @@ +use clippy_utils::msrvs::{self, Msrv}; use rustc_errors::Diag; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; @@ -6,8 +7,8 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, sym}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::trait_ref_of_method; use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item}; +use clippy_utils::{is_no_std_crate, trait_ref_of_method}; use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; @@ -34,19 +35,24 @@ fn result_err_ty<'tcx>( } } -pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { +pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64, msrv: &Msrv) { if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { if cx.effective_visibilities.is_exported(item.owner_id.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - check_result_unit_err(cx, err_ty, fn_header_span); + check_result_unit_err(cx, err_ty, fn_header_span, msrv); } check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); } } -pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) { +pub(super) fn check_impl_item<'tcx>( + cx: &LateContext<'tcx>, + item: &hir::ImplItem<'tcx>, + large_err_threshold: u64, + msrv: &Msrv, +) { // Don't lint if method is a trait's implementation, we can't do anything about those if let hir::ImplItemKind::Fn(ref sig, _) = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) @@ -54,26 +60,31 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem { if cx.effective_visibilities.is_exported(item.owner_id.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - check_result_unit_err(cx, err_ty, fn_header_span); + check_result_unit_err(cx, err_ty, fn_header_span, msrv); } check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); } } -pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) { +pub(super) fn check_trait_item<'tcx>( + cx: &LateContext<'tcx>, + item: &hir::TraitItem<'tcx>, + large_err_threshold: u64, + msrv: &Msrv, +) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { if cx.effective_visibilities.is_exported(item.owner_id.def_id) { - check_result_unit_err(cx, err_ty, fn_header_span); + check_result_unit_err(cx, err_ty, fn_header_span, msrv); } check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); } } } -fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span) { - if err_ty.is_unit() { +fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span, msrv: &Msrv) { + if err_ty.is_unit() && (!is_no_std_crate(cx) || msrv.meets(msrvs::ERROR_IN_CORE)) { span_lint_and_help( cx, RESULT_UNIT_ERR, diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 120c5396a1cd5..2806d4d0e5d61 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,9 +1,13 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::is_else_clause; +use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet}; +use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -54,7 +58,7 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { impl LateLintPass<'_> for IfNotElse { fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { - if let ExprKind::If(cond, _, Some(els)) = e.kind + if let ExprKind::If(cond, cond_inner, Some(els)) = e.kind && let ExprKind::DropTemps(cond) = cond.kind && let ExprKind::Block(..) = els.kind { @@ -79,8 +83,52 @@ impl LateLintPass<'_> for IfNotElse { // } // ``` if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) { - span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help); + match cond.kind { + ExprKind::Unary(UnOp::Not, _) | ExprKind::Binary(_, _, _) => span_lint_and_sugg( + cx, + IF_NOT_ELSE, + e.span, + msg, + "try", + make_sugg(cx, &cond.kind, cond_inner.span, els.span, "..", Some(e.span)).to_string(), + Applicability::MachineApplicable, + ), + _ => span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help), + } } } } } + +fn make_sugg<'a>( + sess: &impl HasSession, + cond_kind: &'a ExprKind<'a>, + cond_inner: Span, + els_span: Span, + default: &'a str, + indent_relative_to: Option, +) -> Cow<'a, str> { + let cond_inner_snip = snippet(sess, cond_inner, default); + let els_snip = snippet(sess, els_span, default); + let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + + let suggestion = match cond_kind { + ExprKind::Unary(UnOp::Not, cond_rest) => { + format!( + "if {} {} else {}", + snippet(sess, cond_rest.span, default), + els_snip, + cond_inner_snip + ) + }, + ExprKind::Binary(_, lhs, rhs) => { + let lhs_snip = snippet(sess, lhs.span, default); + let rhs_snip = snippet(sess, rhs.span, default); + + format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") + }, + _ => String::new(), + }; + + reindent_multiline(suggestion.into(), true, indent) +} diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 6cee7cfaca233..b10206dcd05ec 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use clippy_utils::msrvs::Msrv; -use rustc_attr_parsing::{StabilityLevel, StableSince, RustcVersion}; +use rustc_attr_parsing::{RustcVersion, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index c2030a5ab090b..15650c4f73295 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -135,7 +135,7 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) { .map(|(index, _)| *index) .collect::>(); - let value_name = |index| format!("{}_{index}", slice.ident.name); + let value_name = |index| format!("{}_{}", slice.ident.name, index); if let Some(max_index) = used_indices.iter().max() { let opt_ref = if slice.needs_ref { "ref " } else { "" }; @@ -150,6 +150,18 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) { .collect::>(); let pat_sugg = format!("[{}, ..]", pat_sugg_idents.join(", ")); + let mut suggestions = Vec::new(); + + // Add the binding pattern suggestion + if !slice.pattern_spans.is_empty() { + suggestions.extend(slice.pattern_spans.iter().map(|span| (*span, pat_sugg.clone()))); + } + + // Add the index replacement suggestions + if !slice.index_use.is_empty() { + suggestions.extend(slice.index_use.iter().map(|(index, span)| (*span, value_name(*index)))); + } + span_lint_and_then( cx, INDEX_REFUTABLE_SLICE, @@ -157,28 +169,10 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) { "this binding can be a slice pattern to avoid indexing", |diag| { diag.multipart_suggestion( - "try using a slice pattern here", - slice - .pattern_spans - .iter() - .map(|span| (*span, pat_sugg.clone())) - .collect(), + "replace the binding and indexed access with a slice pattern", + suggestions, Applicability::MaybeIncorrect, ); - - diag.multipart_suggestion( - "and replace the index expressions here", - slice - .index_use - .iter() - .map(|(index, span)| (*span, value_name(*index))) - .collect(), - Applicability::MaybeIncorrect, - ); - - // The lint message doesn't contain a warning about the removed index expression, - // since `filter_lintable_slices` will only return slices where all access indices - // are known at compile time. Therefore, they can be removed without side effects. }, ); } diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index ae2c3e0491f2d..f666ed0a440bf 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::ty::{deref_chain, get_adt_inherent_method}; -use clippy_utils::{higher, is_from_proc_macro}; +use clippy_utils::{higher, is_from_proc_macro, is_in_test}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -42,39 +42,50 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of indexing or slicing. Arrays are special cases, this 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. + /// Checks for usage of indexing or slicing that may panic at runtime. + /// + /// This lint does not report on indexing or slicing operations + /// that always panic, clippy's `out_of_bound_indexing` already + /// handles those cases. /// /// ### 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. /// + /// ### Limitations + /// This lint does not check for the usage of indexing or slicing on strings. These are covered + /// by the more specific `string_slice` lint. + /// /// ### Example /// ```rust,no_run /// // Vector - /// let x = vec![0; 5]; + /// let x = vec![0, 1, 2, 3]; /// /// x[2]; + /// x[100]; /// &x[2..100]; /// /// // Array /// let y = [0, 1, 2, 3]; /// - /// &y[10..100]; - /// &y[10..]; + /// let i = 10; // Could be a runtime value + /// let j = 20; + /// &y[i..j]; /// ``` /// /// Use instead: /// ```no_run - /// # let x = vec![0; 5]; - /// # let y = [0, 1, 2, 3]; + /// # let x = vec![0, 1, 2, 3]; /// x.get(2); + /// x.get(100); /// x.get(2..100); /// - /// y.get(10); - /// y.get(10..100); + /// # let y = [0, 1, 2, 3]; + /// let i = 10; + /// let j = 20; + /// y.get(i..j); /// ``` #[clippy::version = "pre 1.29.0"] pub INDEXING_SLICING, @@ -85,12 +96,14 @@ declare_clippy_lint! { impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]); pub struct IndexingSlicing { + allow_indexing_slicing_in_tests: bool, suppress_restriction_lint_in_const: bool, } impl IndexingSlicing { pub fn new(conf: &'static Conf) -> Self { Self { + allow_indexing_slicing_in_tests: conf.allow_indexing_slicing_in_tests, suppress_restriction_lint_in_const: conf.suppress_restriction_lint_in_const, } } @@ -111,6 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { { let note = "the suggestion might not be applicable in constant blocks"; let ty = cx.typeck_results().expr_ty(array).peel_refs(); + let allowed_in_tests = self.allow_indexing_slicing_in_tests && is_in_test(cx.tcx, expr.hir_id); if let Some(range) = higher::Range::hir(index) { // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] if let ty::Array(_, s) = ty.kind() { @@ -160,6 +174,10 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { (None, None) => return, // [..] is ok. }; + if allowed_in_tests { + return; + } + span_lint_and_then(cx, INDEXING_SLICING, expr.span, "slicing may panic", |diag| { diag.help(help_msg); @@ -198,6 +216,10 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { } } + if allowed_in_tests { + return; + } + span_lint_and_then(cx, INDEXING_SLICING, expr.span, "indexing may panic", |diag| { diag.help("consider using `.get(n)` or `.get_mut(n)` instead"); diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 66d4c40ab5e4e..f3d62b513e840 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -2,8 +2,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_opt; -use rustc_ast::{LitKind}; -use rustc_hir::{Expr, ExprKind, Attribute, AttrArgs, AttrKind}; +use rustc_ast::LitKind; +use rustc_hir::{AttrArgs, AttrKind, Attribute, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3e8315588cc74..d33013ba6638c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -9,6 +9,7 @@ #![feature(iter_partition_in_place)] #![feature(let_chains)] #![feature(never_type)] +#![feature(round_char_boundary)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![feature(unwrap_infallible)] @@ -17,7 +18,8 @@ clippy::missing_docs_in_private_items, clippy::must_use_candidate, rustc::diagnostic_outside_of_impl, - rustc::untranslatable_diagnostic + rustc::untranslatable_diagnostic, + clippy::literal_string_with_formatting_args )] #![warn( trivial_casts, @@ -49,6 +51,7 @@ extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; extern crate rustc_parse; +extern crate rustc_parse_format; extern crate rustc_resolve; extern crate rustc_session; extern crate rustc_span; @@ -196,6 +199,7 @@ mod let_with_type_underscore; mod lifetimes; mod lines_filter_map_ok; mod literal_representation; +mod literal_string_with_formatting_args; mod loops; mod macro_metavars_in_unsafe; mod macro_use; @@ -957,6 +961,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); + store.register_late_pass(|_| Box::new(literal_string_with_formatting_args::LiteralStringWithFormattingArg)); store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp)); store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 35b14776e59f7..8b2eee34a972a 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -643,8 +643,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' // An `impl` lifetime is elidable if it satisfies the following conditions: // - It is used exactly once. -// - That single use is not in a bounded type or `GenericArgs` in a `WherePredicate`. (Note that -// `GenericArgs` are different from `GenericParam`s.) +// - That single use is not in a `WherePredicate`. fn report_elidable_impl_lifetimes<'tcx>( cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>, @@ -658,12 +657,6 @@ fn report_elidable_impl_lifetimes<'tcx>( lifetime, in_where_predicate: false, .. - } - | Usage { - lifetime, - in_bounded_ty: false, - in_generics_arg: false, - .. }, ] = usages.as_slice() { diff --git a/clippy_lints/src/literal_string_with_formatting_args.rs b/clippy_lints/src/literal_string_with_formatting_args.rs new file mode 100644 index 0000000000000..49353a1b76bec --- /dev/null +++ b/clippy_lints/src/literal_string_with_formatting_args.rs @@ -0,0 +1,167 @@ +use rustc_ast::{LitKind, StrStyle}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lexer::is_ident; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_parse_format::{ParseMode, Parser, Piece}; +use rustc_session::declare_lint_pass; +use rustc_span::{BytePos, Span}; + +use clippy_utils::diagnostics::span_lint; +use clippy_utils::mir::enclosing_mir; + +declare_clippy_lint! { + /// ### What it does + /// Checks if string literals have formatting arguments outside of macros + /// using them (like `format!`). + /// + /// ### Why is this bad? + /// It will likely not generate the expected content. + /// + /// ### Example + /// ```no_run + /// let x: Option = None; + /// let y = "hello"; + /// x.expect("{y:?}"); + /// ``` + /// Use instead: + /// ```no_run + /// let x: Option = None; + /// let y = "hello"; + /// x.expect(&format!("{y:?}")); + /// ``` + #[clippy::version = "1.83.0"] + pub LITERAL_STRING_WITH_FORMATTING_ARGS, + suspicious, + "Checks if string literals have formatting arguments" +} + +declare_lint_pass!(LiteralStringWithFormattingArg => [LITERAL_STRING_WITH_FORMATTING_ARGS]); + +fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, spans: &[(Span, Option)]) { + if !spans.is_empty() + && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) + { + let spans = spans + .iter() + .filter_map(|(span, name)| { + if let Some(name) = name { + // We need to check that the name is a local. + if !mir + .var_debug_info + .iter() + .any(|local| !local.source_info.span.from_expansion() && local.name.as_str() == name) + { + return None; + } + } + Some(*span) + }) + .collect::>(); + match spans.len() { + 0 => {}, + 1 => { + span_lint( + cx, + LITERAL_STRING_WITH_FORMATTING_ARGS, + spans, + "this looks like a formatting argument but it is not part of a formatting macro", + ); + }, + _ => { + span_lint( + cx, + LITERAL_STRING_WITH_FORMATTING_ARGS, + spans, + "these look like formatting arguments but are not part of a formatting macro", + ); + }, + } + } +} + +impl LateLintPass<'_> for LiteralStringWithFormattingArg { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + if let ExprKind::Lit(lit) = expr.kind { + let (add, symbol) = match lit.node { + LitKind::Str(symbol, style) => { + let add = match style { + StrStyle::Cooked => 1, + StrStyle::Raw(nb) => nb as usize + 2, + }; + (add, symbol) + }, + _ => return, + }; + let fmt_str = symbol.as_str(); + let lo = expr.span.lo(); + let mut current = fmt_str; + let mut diff_len = 0; + + let mut parser = Parser::new(current, None, None, false, ParseMode::Format); + let mut spans = Vec::new(); + while let Some(piece) = parser.next() { + if let Some(error) = parser.errors.last() { + // We simply ignore the errors and move after them. + if error.span.end >= current.len() { + break; + } + // We find the closest char to where the error location ends. + let pos = current.floor_char_boundary(error.span.end); + // We get the next character. + current = if let Some((next_char_pos, _)) = current[pos..].char_indices().nth(1) { + // We make the parser start from this new location. + ¤t[pos + next_char_pos..] + } else { + break; + }; + diff_len = fmt_str.len() - current.len(); + parser = Parser::new(current, None, None, false, ParseMode::Format); + } else if let Piece::NextArgument(arg) = piece { + let mut pos = arg.position_span; + pos.start += diff_len; + pos.end += diff_len; + + let start = fmt_str[..pos.start].rfind('{').unwrap_or(pos.start); + // If this is a unicode character escape, we don't want to lint. + if start > 1 && fmt_str[..start].ends_with("\\u") { + continue; + } + + if fmt_str[start + 1..].trim_start().starts_with('}') { + // We ignore `{}`. + continue; + } + + let end = fmt_str[start + 1..] + .find('}') + .map_or(pos.end, |found| start + 1 + found) + + 1; + let ident_start = start + 1; + let colon_pos = fmt_str[ident_start..end].find(':'); + let ident_end = colon_pos.unwrap_or(end - 1); + let mut name = None; + if ident_start < ident_end + && let arg = &fmt_str[ident_start..ident_end] + && !arg.is_empty() + && is_ident(arg) + { + name = Some(arg.to_string()); + } else if colon_pos.is_none() { + // Not a `{:?}`. + continue; + } + spans.push(( + expr.span + .with_hi(lo + BytePos((start + add).try_into().unwrap())) + .with_lo(lo + BytePos((end + add).try_into().unwrap())), + name, + )); + } + } + emit_lint(cx, expr, &spans); + } + } +} diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 3c77db84a4054..9f3b0957eab11 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let Some(vis_snip) = vis_span.get_source_text(cx) && let Some(header_snip) = header_span.get_source_text(cx) && let Some(ret_pos) = position_before_rarrow(&header_snip) - && let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output) + && let Some((_, ret_snip)) = suggested_ret(cx, output) { let header_snip = if vis_snip.is_empty() { format!("async {}", &header_snip[..ret_pos]) @@ -82,19 +82,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) }; - let help = format!("make the function `async` and {ret_sugg}"); - diag.span_suggestion( - header_span, - help, - format!("{header_snip}{ret_snip}"), - Applicability::MachineApplicable, - ); + let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)).to_string(); - let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)); - diag.span_suggestion( - block.span, - "move the body of the async block to the enclosing function", - body_snip, + diag.multipart_suggestion( + "make the function `async` and return the output of the future directly", + vec![ + (header_span, format!("{header_snip}{ret_snip}")), + (block.span, body_snip), + ], Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 0e08e2eb83da6..a1951b9da44a9 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -5,9 +5,9 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::TyCtxt; @@ -129,9 +129,7 @@ fn is_not_const(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | DefKind::Ctor(..) | DefKind::AssocConst => false, - DefKind::Fn - | DefKind::AssocFn - | DefKind::Closure => tcx.constness(def_id) == Constness::NotConst, + DefKind::Fn | DefKind::AssocFn | DefKind::Closure => tcx.constness(def_id) == Constness::NotConst, } } diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index 4fee3bf7aa9f5..841adfec4624b 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -43,21 +43,21 @@ impl LateLintPass<'_> for ManualIsPowerOfTwo { && bin_op.node == BinOpKind::Eq { // a.count_ones() == 1 - if let ExprKind::MethodCall(method_name, reciever, [], _) = left.kind + if let ExprKind::MethodCall(method_name, receiver, [], _) = left.kind && method_name.ident.as_str() == "count_ones" - && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && let &Uint(_) = cx.typeck_results().expr_ty(receiver).kind() && check_lit(right, 1) { - build_sugg(cx, expr, reciever, &mut applicability); + build_sugg(cx, expr, receiver, &mut applicability); } // 1 == a.count_ones() - if let ExprKind::MethodCall(method_name, reciever, [], _) = right.kind + if let ExprKind::MethodCall(method_name, receiver, [], _) = right.kind && method_name.ident.as_str() == "count_ones" - && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && let &Uint(_) = cx.typeck_results().expr_ty(receiver).kind() && check_lit(left, 1) { - build_sugg(cx, expr, reciever, &mut applicability); + build_sugg(cx, expr, receiver, &mut applicability); } // a & (a - 1) == 0 @@ -115,8 +115,8 @@ impl LateLintPass<'_> for ManualIsPowerOfTwo { } } -fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, reciever: &Expr<'_>, applicability: &mut Applicability) { - let snippet = snippet_with_applicability(cx, reciever.span, "..", applicability); +fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, applicability: &mut Applicability) { + let snippet = snippet_with_applicability(cx, receiver.span, "..", applicability); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 20984bc40caf3..b72a61a438499 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -74,8 +74,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { // check if using the same bindings as before HirIdMapEntry::Occupied(entry) => return *entry.get() == b_id, } - // the names technically don't have to match; this makes the lint more conservative - && cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id) + // the names technically don't have to match; this makes the lint more conservative + && cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id) && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b) && pat_contains_local(lhs.pat, a_id) && pat_contains_local(rhs.pat, b_id) @@ -149,16 +149,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "", &mut appl); let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "", &mut appl); - diag.span_suggestion( - keep_arm.pat.span, - "or try merging the arm patterns", - format!("{keep_pat_snip} | {move_pat_snip}"), - appl, - ) - .span_suggestion( - adjusted_arm_span(cx, move_arm.span), - "and remove this obsolete arm", - "", + diag.multipart_suggestion( + "or try merging the arm patterns and removing the obsolete arm", + vec![ + (keep_arm.pat.span, format!("{keep_pat_snip} | {move_pat_snip}")), + (adjusted_arm_span(cx, move_arm.span), String::new()), + ], appl, ) .help("try changing either arm body"); diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 64969271764c4..1fd2ebcb54a68 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -27,7 +27,9 @@ mod wild_in_or_pats; use clippy_config::Conf; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; -use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg}; +use clippy_utils::{ + higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, +}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -1059,7 +1061,28 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } redundant_pattern_match::check_match(cx, expr, ex, arms); - single_match::check(cx, ex, arms, expr); + let source_map = cx.tcx.sess.source_map(); + let mut match_comments = span_extract_comments(source_map, expr.span); + // We remove comments from inside arms block. + if !match_comments.is_empty() { + for arm in arms { + for comment in span_extract_comments(source_map, arm.body.span) { + if let Some(index) = match_comments + .iter() + .enumerate() + .find(|(_, cm)| **cm == comment) + .map(|(index, _)| index) + { + match_comments.remove(index); + } + } + } + } + // If there are still comments, it means they are outside of the arms, therefore + // we should not lint. + if match_comments.is_empty() { + single_match::check(cx, ex, arms, expr); + } match_bool::check(cx, ex, arms, expr); overlapping_arms::check(cx, ex, arms); match_wild_enum::check(cx, ex, arms); diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 6f7d690264049..73822314b4b4a 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{ - eq_expr_value, get_parent_expr_for_hir, higher, is_else_clause, is_res_lang_ctor, over, path_res, + SpanlessEq, eq_expr_value, get_parent_expr_for_hir, higher, is_else_clause, is_res_lang_ctor, over, path_res, peel_blocks_with_stmt, }; use rustc_errors::Applicability; @@ -90,7 +90,9 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool } // Recursively check for each `else if let` phrase, - if let Some(ref nested_if_let) = higher::IfLet::hir(cx, if_else) { + if let Some(ref nested_if_let) = higher::IfLet::hir(cx, if_else) + && SpanlessEq::new(cx).eq_expr(nested_if_let.let_expr, if_let.let_expr) + { return check_if_let_inner(cx, nested_if_let); } diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 95a4bf6f60de3..3ca20479f8e00 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -129,7 +129,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. - }) if lit.node.is_str() => pat_ref_count + 1, + }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, _ => pat_ref_count, }; // References are only implicitly added to the pattern, so no overflow here. diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index cf7f276dabb10..b04d761d4860e 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::ExprKind; use rustc_lint::LateContext; use rustc_span::{Span, sym}; @@ -21,6 +22,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: if is_trait_method(cx, expr, sym::Iterator) && let Some(applicability) = is_identity(cx, filter_map_arg) { + // check if the iterator is from an empty array, see issue #12653 + if let ExprKind::MethodCall(_, recv, ..) = expr.kind + && let ExprKind::MethodCall(_, recv2, ..) = recv.kind + && let ExprKind::Array(arr) = recv2.kind + && arr.is_empty() + { + return; + } + span_lint_and_sugg( cx, FILTER_MAP_IDENTITY, diff --git a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index 80703618a1131..1ebb71e251aba 100644 --- a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -19,7 +19,7 @@ fn extract_count_with_applicability( ) -> Option { let start = range.start?; let end = range.end?; - // TODO: This doens't handle if either the start or end are negative literals, or if the start is + // TODO: This doesn't handle if either the start or end are negative literals, or if the start is // not a literal. In the first case, we need to be careful about how we handle computing the // count to avoid overflows. In the second, we may need to add parenthesis to make the // suggestion correct. diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7d1d5d69c9912..810287fa54167 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1864,7 +1864,6 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// let opt: Option = None; /// /// opt.unwrap_or_else(|| 42); @@ -3839,13 +3838,11 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// vec![Some(1)].into_iter().filter(Option::is_some); /// /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning /// vec![Some(1)].into_iter().flatten(); /// ``` #[clippy::version = "1.77.0"] @@ -3865,13 +3862,11 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// vec![Ok::(1)].into_iter().filter(Result::is_ok); /// /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning /// vec![Ok::(1)].into_iter().flatten(); /// ``` #[clippy::version = "1.77.0"] @@ -3969,7 +3964,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// - /// In the aformentioned cases it is not necessary to call `min()` or `max()` + /// In the aforementioned cases it is not necessary to call `min()` or `max()` /// to compare values, it may even cause confusion. /// /// ### Example @@ -4982,6 +4977,10 @@ impl Methods { } map_identity::check(cx, expr, recv, m_arg, name, span); manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv); + crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); + }, + ("map_break" | "map_continue", [m_arg]) => { + crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index 829c118d29163..c41ce2481d741 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -1,9 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_def_path; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_type_diagnostic_item; -use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -11,20 +8,17 @@ use super::NEEDLESS_OPTION_TAKE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place - if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) && has_expr_as_ref_path(cx, recv) { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - NEEDLESS_OPTION_TAKE, - expr.span, - "called `Option::take()` on a temporary value", - "try", - format!( - "{}", - snippet_with_applicability(cx, recv.span, "..", &mut applicability) - ), - applicability, - ); + if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) { + if let Some(function_name) = source_of_temporary_value(recv) { + span_lint_and_note( + cx, + NEEDLESS_OPTION_TAKE, + expr.span, + "called `Option::take()` on a temporary value", + None, + format!("`{function_name}` creates a temporary value, so calling take() has no effect"), + ); + } } } @@ -33,9 +27,24 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { is_type_diagnostic_item(cx, expr_type, sym::Option) } -fn has_expr_as_ref_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(ref_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - return match_def_path(cx, ref_id, &["core", "option", "Option", "as_ref"]); +/// Returns the string of the function call that creates the temporary. +/// When this function is called, we are reasonably certain that the `ExprKind` is either +/// `Call` or `MethodCall` because we already checked that the expression is not +/// `is_syntactic_place_expr()`. +fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> { + match expr.peel_borrows().kind { + ExprKind::Call(function, _) => { + if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind { + if !func_path.segments.is_empty() { + return Some(func_path.segments[0].ident.name.as_str()); + } + } + if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind { + return Some(func_path_segment.ident.name.as_str()); + } + None + }, + ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name.as_str()), + _ => None, } - false } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index c91be33b1cd09..c6d4ef5911ee2 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -129,7 +129,7 @@ fn check_manual_split_once_indirect( let ctxt = expr.span.ctxt(); let mut parents = cx.tcx.hir().parent_iter(expr.hir_id); if let (_, Node::LetStmt(local)) = parents.next()? - && let PatKind::Binding(BindingMode::MUT, iter_binding_id, iter_ident, None) = local.pat.kind + && let PatKind::Binding(BindingMode::MUT, iter_binding_id, _, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? && let mut stmts = enclosing_block @@ -162,16 +162,20 @@ fn check_manual_split_once_indirect( UnwrapKind::Unwrap => ".unwrap()", UnwrapKind::QuestionMark => "?", }; - diag.span_suggestion_verbose( - local.span, - format!("try `{r}split_once`"), - format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"), + + // Add a multipart suggestion + diag.multipart_suggestion( + format!("replace with `{r}split_once`"), + vec![ + ( + local.span, + format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"), + ), + (first.span, String::new()), // Remove the first usage + (second.span, String::new()), // Remove the second usage + ], app, ); - - let remove_msg = format!("remove the `{iter_ident}` usages"); - diag.span_suggestion(first.span, remove_msg.clone(), "", app); - diag.span_suggestion(second.span, remove_msg, "", app); }); } diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 029704882dde2..671c189a98e66 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -6,6 +6,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; 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 itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind}; @@ -122,14 +123,13 @@ pub fn check_for_loop_iter( } else { Applicability::MachineApplicable }; - diag.span_suggestion(expr.span, "use", snippet.to_owned(), applicability); - if !references_to_binding.is_empty() { - diag.multipart_suggestion( - "remove any references to the binding", - references_to_binding, - applicability, - ); - } + + let combined = references_to_binding + .into_iter() + .chain(vec![(expr.span, snippet.to_owned())]) + .collect_vec(); + + diag.multipart_suggestion("remove any references to the binding", combined, applicability); }, ); return true; diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 603916e06c95f..9a45b04d1a624 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_trait_method, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::LateContext; @@ -211,8 +211,10 @@ pub(super) fn check<'tcx>( trigger.vec_name, if is_unstable { "_unstable" } else { "" }, trigger.closure_arg, - if trigger.reverse { - format!("std::cmp::Reverse({})", trigger.closure_body) + if let Some(std_or_core) = std_or_core(cx) + && trigger.reverse + { + format!("{}::cmp::Reverse({})", std_or_core, trigger.closure_body) } else { trigger.closure_body.to_string() }, diff --git a/clippy_lints/src/missing_const_for_thread_local.rs b/clippy_lints/src/missing_const_for_thread_local.rs index 9a44a3c980c0e..e2ca4458edaa0 100644 --- a/clippy_lints/src/missing_const_for_thread_local.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -27,14 +27,12 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// thread_local! { /// static BUF: String = String::new(); /// } /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning /// thread_local! { /// static BUF: String = const { String::new() }; /// } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 9e44bb02c56fa..7feff7e4d3f13 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, Stmt, StmtKind, - UnsafeSource, StructTailExpr, is_range_literal, + StructTailExpr, UnsafeSource, is_range_literal, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs index d369978b8be80..2083f2bf628d0 100644 --- a/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/clippy_lints/src/operators/numeric_arithmetic.rs @@ -43,8 +43,8 @@ impl Context { _ => (), } - let (_, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); - if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { + let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); + if l_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.expr_id = Some(expr.hir_id); } diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 37f5dd5583bfb..031f09310590b 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use rustc_ast::ast::BinOpKind::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}; use rustc_ast::ast::{BinOpKind, Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -12,6 +13,7 @@ declare_clippy_lint! { /// and suggests to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without /// parentheses + /// * mixed usage of bitmasking and bit shifting operators without parentheses /// /// ### Why is this bad? /// Not everyone knows the precedence of those operators by @@ -20,6 +22,7 @@ declare_clippy_lint! { /// /// ### Example /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 + /// * `0x2345 & 0xF000 >> 12` equals 5, while `(0x2345 & 0xF000) >> 12` equals 2 #[clippy::version = "pre 1.29.0"] pub PRECEDENCE, complexity, @@ -51,8 +54,13 @@ impl EarlyLintPass for Precedence { return; } let mut applicability = Applicability::MachineApplicable; - match (is_arith_expr(left), is_arith_expr(right)) { - (true, true) => { + match (op, get_bin_opt(left), get_bin_opt(right)) { + ( + BitAnd | BitOr | BitXor, + Some(Shl | Shr | Add | Div | Mul | Rem | Sub), + Some(Shl | Shr | Add | Div | Mul | Rem | Sub), + ) + | (Shl | Shr, Some(Add | Div | Mul | Rem | Sub), Some(Add | Div | Mul | Rem | Sub)) => { let sugg = format!( "({}) {} ({})", snippet_with_applicability(cx, left.span, "..", &mut applicability), @@ -61,7 +69,8 @@ impl EarlyLintPass for Precedence { ); span_sugg(expr, sugg, applicability); }, - (true, false) => { + (BitAnd | BitOr | BitXor, Some(Shl | Shr | Add | Div | Mul | Rem | Sub), _) + | (Shl | Shr, Some(Add | Div | Mul | Rem | Sub), _) => { let sugg = format!( "({}) {} {}", snippet_with_applicability(cx, left.span, "..", &mut applicability), @@ -70,7 +79,8 @@ impl EarlyLintPass for Precedence { ); span_sugg(expr, sugg, applicability); }, - (false, true) => { + (BitAnd | BitOr | BitXor, _, Some(Shl | Shr | Add | Div | Mul | Rem | Sub)) + | (Shl | Shr, _, Some(Add | Div | Mul | Rem | Sub)) => { let sugg = format!( "{} {} ({})", snippet_with_applicability(cx, left.span, "..", &mut applicability), @@ -79,27 +89,20 @@ impl EarlyLintPass for Precedence { ); span_sugg(expr, sugg, applicability); }, - (false, false) => (), + _ => (), } } } } -fn is_arith_expr(expr: &Expr) -> bool { +fn get_bin_opt(expr: &Expr) -> Option { match expr.kind { - ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op), - _ => false, + ExprKind::Binary(Spanned { node: op, .. }, _, _) => Some(op), + _ => None, } } #[must_use] fn is_bit_op(op: BinOpKind) -> bool { - use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr}; matches!(op, BitXor | BitAnd | BitOr | Shl | Shr) } - -#[must_use] -fn is_arith_op(op: BinOpKind) -> bool { - use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub}; - matches!(op, Add | Sub | Mul | Div | Rem) -} diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 77abe7151f071..ffc3b86c502e3 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -59,7 +59,7 @@ pub struct QuestionMark { /// As for why we need this in the first place: try_block_depth_stack: Vec, /// Keeps track of the number of inferred return type closures we are inside, to avoid problems - /// with the `Err(x.into())` expansion being ambiguious. + /// with the `Err(x.into())` expansion being ambiguous. inferred_ret_closure_stack: u16, } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 8e3472b1b5a1a..7038b19d27596 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -85,7 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr)); let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); - let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence() > ExprPrecedence::Prefix); + let needs_parens_for_prefix = + parent_expr.is_some_and(|parent| parent.precedence() > ExprPrecedence::Prefix); if expr_ty == indexed_ty { if expr_ref_count > indexed_ref_count { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 7ae0310b6d996..83199ba0f7076 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,6 +1,9 @@ +use std::ops::ControlFlow; + use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; -use clippy_utils::visitors::is_local_used; +use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; @@ -175,9 +178,31 @@ fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second false } +/// Checks if the given local is used, except for in child expression of `except`. +/// +/// This is a version of [`is_local_used`](clippy_utils::visitors::is_local_used), used to +/// implement the fix for . +pub fn is_local_used_except<'tcx>( + cx: &LateContext<'tcx>, + visitable: impl Visitable<'tcx>, + id: HirId, + except: Option, +) -> bool { + for_each_expr(cx, visitable, |e| { + if except.is_some_and(|it| it == e.hir_id) { + ControlFlow::Continue(Descend::No) + } else if path_to_local_id(e, id) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::Yes) + } + }) + .is_some() +} + fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) { let (lint, msg) = match find_init(cx, pat.hir_id) { - Some(expr) if is_self_shadow(cx, pat, expr, shadowed) => { + Some((expr, _)) if is_self_shadow(cx, pat, expr, shadowed) => { let msg = format!( "`{}` is shadowed by itself in `{}`", snippet(cx, pat.span, "_"), @@ -185,7 +210,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) ); (SHADOW_SAME, msg) }, - Some(expr) if is_local_used(cx, expr, shadowed) => { + Some((expr, except)) if is_local_used_except(cx, expr, shadowed, except) => { let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_")); (SHADOW_REUSE, msg) }, @@ -232,15 +257,32 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_ /// Finds the "init" expression for a pattern: `let = ;` (or `if let`) or /// `match { .., => .., .. }` -fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { - for (_, node) in cx.tcx.hir().parent_iter(hir_id) { +/// +/// For closure arguments passed to a method call, returns the method call, and the `HirId` of the +/// closure (which will later be skipped). This is for +fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<(&'tcx Expr<'tcx>, Option)> { + for (hir_id, node) in cx.tcx.hir().parent_iter(hir_id) { let init = match node { - Node::Arm(_) | Node::Pat(_) => continue, + Node::Arm(_) | Node::Pat(_) | Node::PatField(_) | Node::Param(_) => continue, Node::Expr(expr) => match expr.kind { - ExprKind::Match(e, _, _) | ExprKind::Let(&LetExpr { init: e, .. }) => Some(e), + ExprKind::Match(e, _, _) | ExprKind::Let(&LetExpr { init: e, .. }) => Some((e, None)), + // If we're a closure argument, then a parent call is also an associated item. + ExprKind::Closure(_) => { + if let Some((_, node)) = cx.tcx.hir().parent_iter(hir_id).next() { + match node { + Node::Expr(expr) => match expr.kind { + ExprKind::MethodCall(_, _, _, _) | ExprKind::Call(_, _) => Some((expr, Some(hir_id))), + _ => None, + }, + _ => None, + } + } else { + None + } + }, _ => None, }, - Node::LetStmt(local) => local.init, + Node::LetStmt(local) => local.init.map(|init| (init, None)), _ => None, }; return init; diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 1a5b958e6a673..c690696aefc19 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -99,16 +99,10 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { snippet(cx, apa.last_bind_ident.span, ".."), ) }; - diag.span_suggestion_verbose( - apa.first_stmt_span, + + diag.multipart_suggestion_verbose( "merge the temporary construction with its single usage", - stmt, - Applicability::MaybeIncorrect, - ); - diag.span_suggestion( - apa.last_stmt_span, - "remove separated single usage", - "", + vec![(apa.first_stmt_span, stmt), (apa.last_stmt_span, String::new())], Applicability::MaybeIncorrect, ); }, diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index bb11daecc07da..9737b84cdb9c7 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -86,7 +86,8 @@ impl LateLintPass<'_> for SingleRangeInVecInit { return; }; - let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], StructTailExpr::None) = inner_expr.kind else { + let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], StructTailExpr::None) = inner_expr.kind + else { return; }; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index e09c07060065c..2925f355d0b6d 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -370,12 +370,10 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// let _ = "str".to_string(); /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning /// let _ = "str".to_owned(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -424,13 +422,11 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// let msg = String::from("Hello World"); /// let _ = msg.to_string(); /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning /// let msg = String::from("Hello World"); /// let _ = msg.clone(); /// ``` diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 0702f6d1e74b2..d2727968c0c95 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_context; -use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, is_local_used}; +use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -71,25 +71,38 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { local.span, "this let-binding has unit value", |diag| { + let mut suggestions = Vec::new(); + + // Suggest omitting the `let` binding if let Some(expr) = &local.init { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; - diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app); + suggestions.push((local.span, format!("{snip};"))); } - if let PatKind::Binding(_, binding_hir_id, ident, ..) = local.pat.kind + // If this is a binding pattern, we need to add suggestions to remove any usages + // of the variable + if let PatKind::Binding(_, binding_hir_id, ..) = local.pat.kind && let Some(body_id) = cx.enclosing_body.as_ref() - && let body = cx.tcx.hir().body(*body_id) - && is_local_used(cx, body, binding_hir_id) { - let identifier = ident.as_str(); + let body = cx.tcx.hir().body(*body_id); + + // Collect variable usages let mut visitor = UnitVariableCollector::new(binding_hir_id); walk_body(&mut visitor, body); - visitor.spans.into_iter().for_each(|span| { - let msg = - format!("variable `{identifier}` of type `()` can be replaced with explicit `()`"); - diag.span_suggestion(span, msg, "()", Applicability::MachineApplicable); - }); + + // Add suggestions for replacing variable usages + suggestions.extend(visitor.spans.into_iter().map(|span| (span, "()".to_string()))); + } + + // Emit appropriate diagnostic based on whether there are usages of the let binding + if !suggestions.is_empty() { + let message = if suggestions.len() == 1 { + "omit the `let` binding" + } else { + "omit the `let` binding and replace variable usages with `()`" + }; + diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable); } }, ); diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 0f4bd286145a8..47d6fe7db7667 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -25,13 +25,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { return; } - let (reciever, args) = match expr.kind { + let (receiver, args) = match expr.kind { ExprKind::Call(_, args) => (None, args), ExprKind::MethodCall(_, receiver, args, _) => (Some(receiver), args), _ => return, }; - let args_to_recover = reciever + let args_to_recover = receiver .into_iter() .chain(args) .filter(|arg| { diff --git a/clippy_lints/src/unnecessary_literal_bound.rs b/clippy_lints/src/unnecessary_literal_bound.rs index 80ce67111261d..8165a45bc5baa 100644 --- a/clippy_lints/src/unnecessary_literal_bound.rs +++ b/clippy_lints/src/unnecessary_literal_bound.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// - /// This leaves the caller unable to use the `&str` as `&'static str`, causing unneccessary allocations or confusion. + /// This leaves the caller unable to use the `&str` as `&'static str`, causing unnecessary allocations or confusion. /// This is also most likely what you meant to write. /// /// ### Example diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index 0a90d31db7e14..1df229c330eb3 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; -use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, UnOp, StructTailExpr}; +use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, StructTailExpr, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -63,7 +63,9 @@ impl LateLintPass<'_> for UnnecessaryStruct { // all fields match, no base given path.span }, - (Some(path), StructTailExpr::Base(base)) if base_is_suitable(cx, expr, base) && path_matches_base(path, base) => { + (Some(path), StructTailExpr::Base(base)) + if base_is_suitable(cx, expr, base) && path_matches_base(path, base) => + { // all fields match, has base: ensure that the path of the base matches base.span }, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3b05abc546f47..7ffab81a5444c 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; -use clippy_utils::sugg::Sugg; +use clippy_utils::sugg::{DiagExt as _, Sugg}; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; +use clippy_utils::{ + get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, +}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; @@ -10,7 +12,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -382,3 +384,50 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } } + +/// Check if `arg` is a `Into::into` or `From::from` applied to `receiver` to give `expr`, through a +/// higher-order mapping function. +pub fn check_function_application(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { + if has_eligible_receiver(cx, recv, expr) + && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From)) + && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind() + && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice() + && same_type_and_consts(from_ty, to_ty) + { + span_lint_and_then( + cx, + USELESS_CONVERSION, + expr.span.with_lo(recv.span.hi()), + format!("useless conversion to the same type: `{from_ty}`"), + |diag| { + diag.suggest_remove_item( + cx, + expr.span.with_lo(recv.span.hi()), + "consider removing", + Applicability::MachineApplicable, + ); + }, + ); + } +} + +fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) -> bool { + let recv_ty = cx.typeck_results().expr_ty(recv); + if is_inherent_method_call(cx, expr) + && let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did) + { + if let Some(diag_name) = cx.tcx.get_diagnostic_name(recv_ty_defid) + && matches!(diag_name, sym::Option | sym::Result) + { + return true; + } + + if cx.tcx.is_diagnostic_item(sym::ControlFlow, recv_ty_defid) { + return true; + } + } + if is_trait_method(cx, expr, sym::Iterator) { + return true; + } + false +} diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 521bf6a5fede9..d2970c93f8e91 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -3,8 +3,8 @@ use rustc_ast::LitIntType; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ - self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, - ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, StructTailExpr, + self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, + FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, StructTailExpr, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -625,7 +625,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ExprKind::UnsafeBinderCast(..) => { unimplemented!("unsafe binders are not implemented yet"); - } + }, } } diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 5483e80f932e1..bfcce81c498a8 100644 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -1,8 +1,7 @@ use crate::utils::internal_lints::lint_without_lint_pass::is_lint_ref_type; use clippy_utils::diagnostics::span_lint_and_help; use regex::Regex; -use rustc_ast as ast; -use rustc_hir::{Item, ItemKind, Mutability}; +use rustc_hir::{Attribute, Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -51,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { .hir() .attrs(item.hir_id()) .iter() - .filter_map(|attr| ast::Attribute::doc_str(attr).map(|sym| (sym, attr))); + .filter_map(|attr| Attribute::doc_str(attr).map(|sym| (sym, attr))); if is_lint_ref_type(cx, ty) { for (line, attr) in lines { let cur_line = line.as_str().trim(); diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 9e400d2391f02..e454427adde1b 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Call(func, [arg]) = &expr.kind && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() - && match_def_path(cx, *def_id, &paths::SYMBOL_INTERN) + && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) && let value = Symbol::intern(&arg).as_u32() && let Some(&def_id) = self.symbol_map.get(&value) diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 496343d82c8d6..dac1951489ca8 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -3,6 +3,7 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{is_lint_allowed, match_def_path, paths}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; @@ -13,7 +14,6 @@ use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; -use {rustc_ast as ast, rustc_hir as hir}; declare_clippy_lint! { /// ### What it does @@ -249,11 +249,11 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option { let attrs = cx.tcx.hir().attrs(item.hir_id()); attrs.iter().find_map(|attr| { - if let ast::AttrKind::Normal(attr_kind) = &attr.kind + if let hir::AttrKind::Normal(attr_kind) = &attr.kind // Identify attribute - && let [tool_name, attr_name] = &attr_kind.item.path.segments[..] - && tool_name.ident.name == sym::clippy - && attr_name.ident.name == sym::version + && let [tool_name, attr_name] = &attr_kind.path.segments[..] + && tool_name.name == sym::clippy + && attr_name.name == sym::version && let Some(version) = attr.value_str() { Some(version) diff --git a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs index 3742be0e103d6..49aad881994e9 100644 --- a/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs +++ b/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs @@ -1,29 +1,29 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; -use clippy_utils::{match_function_call, paths}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does /// - /// Detects symbol comparision using `Symbol::intern`. + /// Detects symbol comparison using `Symbol::intern`. /// /// ### Why is this bad? /// - /// Comparision via `Symbol::as_str()` is faster if the interned symbols are not reused. + /// Comparison via `Symbol::as_str()` is faster if the interned symbols are not reused. /// /// ### Example /// /// None, see suggestion. pub SLOW_SYMBOL_COMPARISONS, internal, - "detects slow comparisions of symbol" + "detects slow comparisons of symbol" } declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]); @@ -34,7 +34,12 @@ fn check_slow_comparison<'tcx>( op2: &'tcx Expr<'tcx>, ) -> Option<(Span, String)> { if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL) - && let Some([symbol_name_expr]) = match_function_call(cx, op2, &paths::SYMBOL_INTERN) + && let ExprKind::Call(fun, args) = op2.kind + && let ExprKind::Path(ref qpath) = fun.kind + && cx + .tcx + .is_diagnostic_item(sym::SymbolIntern, cx.qpath_res(qpath, fun.hir_id).opt_def_id()?) + && let [symbol_name_expr] = args && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr) { Some((op1.span, symbol_name)) diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index 4a13c10166f86..a702e0785a960 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -2,13 +2,14 @@ use ControlFlow::{Break, Continue}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, get_enclosing_block, match_any_def_paths, match_def_path, path_to_local_id, paths}; use rustc_ast::Mutability; +use rustc_ast::visit::visit_opt; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_span::{Span, sym}; use std::ops::ControlFlow; declare_clippy_lint! { @@ -22,6 +23,17 @@ declare_clippy_lint! { /// which can eventually lead to resource exhaustion, so it's recommended to call `wait()` in long-running applications. /// Such processes are called "zombie processes". /// + /// To reduce the rate of false positives, if the spawned process is assigned to a binding, the lint actually works the other way around; it + /// conservatively checks that all uses of a variable definitely don't call `wait()` and only then emits a warning. + /// For that reason, a seemingly unrelated use can get called out as calling `wait()` in help messages. + /// + /// ### Control flow + /// If a `wait()` call exists in an if/then block but not in the else block (or there is no else block), + /// then this still gets linted as not calling `wait()` in all code paths. + /// Likewise, when early-returning from the function, `wait()` calls that appear after the return expression + /// are also not accepted. + /// In other words, the `wait()` call must be unconditionally reachable after the spawn expression. + /// /// ### Example /// ```rust /// use std::process::Command; @@ -53,26 +65,47 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { if let PatKind::Binding(_, local_id, ..) = local.pat.kind && let Some(enclosing_block) = get_enclosing_block(cx, expr.hir_id) => { - let mut vis = WaitFinder::WalkUpTo(cx, local_id); - - // If it does have a `wait()` call, we're done. Don't lint. - if let Break(BreakReason::WaitFound) = walk_block(&mut vis, enclosing_block) { - return; - } + let mut vis = WaitFinder { + cx, + local_id, + state: VisitorState::WalkUpToLocal, + early_return: None, + missing_wait_branch: None, + }; + + let res = ( + walk_block(&mut vis, enclosing_block), + vis.missing_wait_branch, + vis.early_return, + ); + + let cause = match res { + (Break(MaybeWait(wait_span)), _, Some(return_span)) => { + Cause::EarlyReturn { wait_span, return_span } + }, + (Break(MaybeWait(_)), _, None) => return, + (Continue(()), None, _) => Cause::NeverWait, + (Continue(()), Some(MissingWaitBranch::MissingElse { if_span, wait_span }), _) => { + Cause::MissingElse { wait_span, if_span } + }, + (Continue(()), Some(MissingWaitBranch::MissingWaitInBranch { branch_span, wait_span }), _) => { + Cause::MissingWaitInBranch { wait_span, branch_span } + }, + }; // Don't emit a suggestion since the binding is used later - check(cx, expr, false); + check(cx, expr, cause, false); }, Node::LetStmt(&LetStmt { pat, .. }) if let PatKind::Wild = pat.kind => { // `let _ = child;`, also dropped immediately without `wait()`ing - check(cx, expr, true); + check(cx, expr, Cause::NeverWait, true); }, Node::Stmt(&Stmt { kind: StmtKind::Semi(_), .. }) => { // Immediately dropped. E.g. `std::process::Command::new("echo").spawn().unwrap();` - check(cx, expr, true); + check(cx, expr, Cause::NeverWait, true); }, _ => {}, } @@ -80,21 +113,10 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { } } -enum BreakReason { - WaitFound, - EarlyReturn, -} +struct MaybeWait(Span); /// A visitor responsible for finding a `wait()` call on a local variable. /// -/// Conditional `wait()` calls are assumed to not call wait: -/// ```ignore -/// let mut c = Command::new("").spawn().unwrap(); -/// if true { -/// c.wait(); -/// } -/// ``` -/// /// Note that this visitor does NOT explicitly look for `wait()` calls directly, but rather does the /// inverse -- checking if all uses of the local are either: /// - a field access (`child.{stderr,stdin,stdout}`) @@ -104,43 +126,50 @@ enum BreakReason { /// /// None of these are sufficient to prevent zombie processes. /// Doing it like this means more FNs, but FNs are better than FPs. -/// -/// `return` expressions, conditional or not, short-circuit the visitor because -/// if a `wait()` call hadn't been found at that point, it might never reach one at a later point: -/// ```ignore -/// let mut c = Command::new("").spawn().unwrap(); -/// if true { -/// return; // Break(BreakReason::EarlyReturn) -/// } -/// c.wait(); // this might not be reachable -/// ``` -enum WaitFinder<'a, 'tcx> { - WalkUpTo(&'a LateContext<'tcx>, HirId), - Found(&'a LateContext<'tcx>, HirId), +struct WaitFinder<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + local_id: HirId, + state: VisitorState, + early_return: Option, + // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targetted help + // messages + missing_wait_branch: Option, +} + +#[derive(PartialEq)] +enum VisitorState { + WalkUpToLocal, + LocalFound, +} + +#[derive(Copy, Clone)] +enum MissingWaitBranch { + MissingElse { if_span: Span, wait_span: Span }, + MissingWaitInBranch { branch_span: Span, wait_span: Span }, } impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - type Result = ControlFlow; + type Result = ControlFlow; fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { - if let Self::WalkUpTo(cx, local_id) = *self + if self.state == VisitorState::WalkUpToLocal && let PatKind::Binding(_, pat_id, ..) = l.pat.kind - && local_id == pat_id + && self.local_id == pat_id { - *self = Self::Found(cx, local_id); + self.state = VisitorState::LocalFound; } walk_local(self, l) } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { - let Self::Found(cx, local_id) = *self else { + if self.state != VisitorState::LocalFound { return walk_expr(self, ex); - }; + } - if path_to_local_id(ex, local_id) { - match cx.tcx.parent_hir_node(ex.hir_id) { + if path_to_local_id(ex, self.local_id) { + match self.cx.tcx.parent_hir_node(ex.hir_id) { Node::Stmt(Stmt { kind: StmtKind::Semi(_), .. @@ -148,29 +177,33 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { Node::Expr(expr) if let ExprKind::Field(..) = expr.kind => {}, Node::Expr(expr) if let ExprKind::AddrOf(_, Mutability::Not, _) = expr.kind => {}, Node::Expr(expr) - if let Some(fn_did) = fn_def_id(cx, expr) - && match_any_def_paths(cx, fn_did, &[&paths::CHILD_ID, &paths::CHILD_KILL]).is_some() => {}, + if let Some(fn_did) = fn_def_id(self.cx, expr) + && match_any_def_paths(self.cx, fn_did, &[&paths::CHILD_ID, &paths::CHILD_KILL]).is_some() => { + }, // Conservatively assume that all other kinds of nodes call `.wait()` somehow. - _ => return Break(BreakReason::WaitFound), + _ => return Break(MaybeWait(ex.span)), } } else { match ex.kind { - ExprKind::Ret(..) => return Break(BreakReason::EarlyReturn), + ExprKind::Ret(e) => { + visit_opt!(self, visit_expr, e); + if self.early_return.is_none() { + self.early_return = Some(ex.span); + } + + return Continue(()); + }, ExprKind::If(cond, then, None) => { walk_expr(self, cond)?; - // A `wait()` call in an if expression with no else is not enough: - // - // let c = spawn(); - // if true { - // c.wait(); - // } - // - // This might not call wait(). However, early returns are propagated, - // because they might lead to a later wait() not being called. - if let Break(BreakReason::EarlyReturn) = walk_expr(self, then) { - return Break(BreakReason::EarlyReturn); + if let Break(MaybeWait(wait_span)) = walk_expr(self, then) + && self.missing_wait_branch.is_none() + { + self.missing_wait_branch = Some(MissingWaitBranch::MissingElse { + if_span: ex.span, + wait_span, + }); } return Continue(()); @@ -179,22 +212,31 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { ExprKind::If(cond, then, Some(else_)) => { walk_expr(self, cond)?; - #[expect(clippy::unnested_or_patterns)] match (walk_expr(self, then), walk_expr(self, else_)) { - (Continue(()), Continue(())) + (Continue(()), Continue(())) => {}, // `wait()` in one branch but nothing in the other does not count - | (Continue(()), Break(BreakReason::WaitFound)) - | (Break(BreakReason::WaitFound), Continue(())) => {}, - - // `wait()` in both branches is ok - (Break(BreakReason::WaitFound), Break(BreakReason::WaitFound)) => { - return Break(BreakReason::WaitFound); + (Continue(()), Break(MaybeWait(wait_span))) => { + if self.missing_wait_branch.is_none() { + self.missing_wait_branch = Some(MissingWaitBranch::MissingWaitInBranch { + branch_span: ex.span.shrink_to_lo().to(then.span), + wait_span, + }); + } + }, + (Break(MaybeWait(wait_span)), Continue(())) => { + if self.missing_wait_branch.is_none() { + self.missing_wait_branch = Some(MissingWaitBranch::MissingWaitInBranch { + branch_span: then.span.shrink_to_hi().to(else_.span), + wait_span, + }); + } }, - // Propagate early returns in either branch - (Break(BreakReason::EarlyReturn), _) | (_, Break(BreakReason::EarlyReturn)) => { - return Break(BreakReason::EarlyReturn); + // `wait()` in both branches is ok + (Break(MaybeWait(wait_span)), Break(MaybeWait(_))) => { + self.missing_wait_branch = None; + return Break(MaybeWait(wait_span)); }, } @@ -208,8 +250,40 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { } fn nested_visit_map(&mut self) -> Self::Map { - let (Self::Found(cx, _) | Self::WalkUpTo(cx, _)) = self; - cx.tcx.hir() + self.cx.tcx.hir() + } +} + +#[derive(Copy, Clone)] +enum Cause { + /// No call to `wait()` at all + NeverWait, + /// `wait()` call exists, but not all code paths definitely lead to one due to + /// an early return + EarlyReturn { wait_span: Span, return_span: Span }, + /// `wait()` call exists in some if branches but not this one + MissingWaitInBranch { wait_span: Span, branch_span: Span }, + /// `wait()` call exists in an if/then branch but it is missing an else block + MissingElse { wait_span: Span, if_span: Span }, +} + +impl Cause { + fn message(self) -> &'static str { + match self { + Cause::NeverWait => "spawned process is never `wait()`ed on", + Cause::EarlyReturn { .. } | Cause::MissingWaitInBranch { .. } | Cause::MissingElse { .. } => { + "spawned process is not `wait()`ed on in all code paths" + }, + } + } + + fn fallback_help(self) -> &'static str { + match self { + Cause::NeverWait => "consider calling `.wait()`", + Cause::EarlyReturn { .. } | Cause::MissingWaitInBranch { .. } | Cause::MissingElse { .. } => { + "consider calling `.wait()` in all code paths" + }, + } } } @@ -220,7 +294,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { /// `let _ = ;`. /// /// This checks if the program doesn't unconditionally exit after the spawn expression. -fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, emit_suggestion: bool) { +fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Cause, emit_suggestion: bool) { let Some(block) = get_enclosing_block(cx, spawn_expr.hir_id) else { return; }; @@ -234,27 +308,46 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, emit_sugges return; } - span_lint_and_then( - cx, - ZOMBIE_PROCESSES, - spawn_expr.span, - "spawned process is never `wait()`ed on", - |diag| { - if emit_suggestion { - diag.span_suggestion( - spawn_expr.span.shrink_to_hi(), - "try", - ".wait()", - Applicability::MaybeIncorrect, + span_lint_and_then(cx, ZOMBIE_PROCESSES, spawn_expr.span, cause.message(), |diag| { + match cause { + Cause::EarlyReturn { wait_span, return_span } => { + diag.span_note( + return_span, + "no `wait()` call exists on the code path to this early return", ); - } else { - diag.note("consider calling `.wait()`"); - } + diag.span_note( + wait_span, + "`wait()` call exists, but it is unreachable due to the early return", + ); + }, + Cause::MissingWaitInBranch { wait_span, branch_span } => { + diag.span_note(branch_span, "`wait()` is not called in this if branch"); + diag.span_note(wait_span, "`wait()` is called in the other branch"); + }, + Cause::MissingElse { if_span, wait_span } => { + diag.span_note( + if_span, + "this if expression has a `wait()` call, but it is missing an else block", + ); + diag.span_note(wait_span, "`wait()` called here"); + }, + Cause::NeverWait => {}, + } + + if emit_suggestion { + diag.span_suggestion( + spawn_expr.span.shrink_to_hi(), + "try", + ".wait()", + Applicability::MaybeIncorrect, + ); + } else { + diag.help(cause.fallback_help()); + } - diag.note("not doing so might leave behind zombie processes") - .note("see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning"); - }, - ); + diag.note("not doing so might leave behind zombie processes") + .note("see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning"); + }); } /// Checks if the given expression exits the process. diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 61476a82ba006..73fefbcd5705c 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2024-11-28 +nightly-2024-12-26 ``` diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils/mod.rs similarity index 100% rename from clippy_utils/src/ast_utils.rs rename to clippy_utils/src/ast_utils/mod.rs diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 922afffb8767d..09de5c055379f 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -133,11 +133,7 @@ fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: } } -pub fn get_unique_attr<'a, A: AttributeExt>( - sess: &'a Session, - attrs: &'a [A], - name: &'static str, -) -> Option<&'a A> { +pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: &'static str) -> Option<&'a A> { let mut unique_attr: Option<&A> = None; for attr in get_attr(sess, attrs, name) { if let Some(duplicate) = unique_attr { diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index d216879cbd25e..4e12577b6df6b 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -8,7 +8,7 @@ use crate::ty::is_type_diagnostic_item; use rustc_ast::ast; use rustc_hir as hir; -use rustc_hir::{Arm, Block, Expr, ExprKind, StructTailExpr, HirId, LoopSource, MatchSource, Node, Pat, QPath}; +use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr}; use rustc_lint::LateContext; use rustc_span::{Span, sym, symbol}; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 4b604f658b8d6..ed52c481de124 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -7,10 +7,10 @@ use rustc_data_structures::fx::FxHasher; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, - ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, - LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty, - TyKind, StructTailExpr, + AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, + ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, + Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, + TyKind, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -386,7 +386,7 @@ impl HirEqInterExpr<'_, '_, '_> { self.eq_qpath(l_path, r_path) && match (lo, ro) { (StructTailExpr::Base(l),StructTailExpr::Base(r)) => self.eq_expr(l, r), - (StructTailExpr::None, StructTailExpr::None) => true, + (StructTailExpr::None, StructTailExpr::None) | (StructTailExpr::DefaultFields(_), StructTailExpr::DefaultFields(_)) => true, _ => false, } @@ -473,10 +473,10 @@ impl HirEqInterExpr<'_, '_, '_> { (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, // Use explicit match for now since ConstArg is undergoing flux. - (ConstArgKind::Path(..), ConstArgKind::Anon(..)) | (ConstArgKind::Anon(..), ConstArgKind::Path(..)) - | (ConstArgKind::Infer(..), _) | (_, ConstArgKind::Infer(..)) => { - false - }, + (ConstArgKind::Path(..), ConstArgKind::Anon(..)) + | (ConstArgKind::Anon(..), ConstArgKind::Path(..)) + | (ConstArgKind::Infer(..), _) + | (_, ConstArgKind::Infer(..)) => false, } } @@ -1043,7 +1043,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { if let Some(ty) = ty { self.hash_ty(ty); } - } + }, ExprKind::Err(_) => {}, } } @@ -1255,7 +1255,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, TyKind::UnsafeBinder(binder) => { self.hash_ty(binder.inner_ty); - } + }, TyKind::Err(_) | TyKind::Infer | TyKind::Never diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 02bbddb413a9a..77c597f853489 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1960,43 +1960,6 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { }) } -/// Matches a function call with the given path and returns the arguments. -/// -/// Usage: -/// -/// ```rust,ignore -/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX); -/// ``` -/// This function is deprecated. Use [`match_function_call_with_def_id`]. -pub fn match_function_call<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - path: &[&str], -) -> Option<&'tcx [Expr<'tcx>]> { - if let ExprKind::Call(fun, args) = expr.kind - && let ExprKind::Path(ref qpath) = fun.kind - && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() - && match_def_path(cx, fun_def_id, path) - { - return Some(args); - }; - None -} - -pub fn match_function_call_with_def_id<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - fun_def_id: DefId, -) -> Option<&'tcx [Expr<'tcx>]> { - if let ExprKind::Call(fun, args) = expr.kind - && let ExprKind::Path(ref qpath) = fun.kind - && cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id) - { - return Some(args); - }; - None -} - /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if /// any. /// @@ -2273,15 +2236,19 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> { } pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { - cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| { - attr.name_or_empty() == sym::no_std - }) + cx.tcx + .hir() + .attrs(hir::CRATE_HIR_ID) + .iter() + .any(|attr| attr.name_or_empty() == sym::no_std) } pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { - cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| { - attr.name_or_empty() == sym::no_core - }) + cx.tcx + .hir() + .attrs(hir::CRATE_HIR_ID) + .iter() + .any(|attr| attr.name_or_empty() == sym::no_core) } /// Check if parent of a hir node is a trait implementation block. @@ -2980,12 +2947,18 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// /// Comments are returned wrapped with their relevant delimiters pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { + span_extract_comments(sm, span).join("\n") +} + +/// Returns all the comments a given span contains. +/// +/// Comments are returned wrapped with their relevant delimiters. +pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec { let snippet = sm.span_to_snippet(span).unwrap_or_default(); - let res = tokenize_with_text(&snippet) + tokenize_with_text(&snippet) .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) - .map(|(_, s, _)| s) - .join("\n"); - res + .map(|(_, s, _)| s.to_string()) + .collect::>() } pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 1e6368fab368d..98bcedecccc65 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -1,5 +1,5 @@ use rustc_ast::attr::AttributeExt; -use rustc_attr_parsing::{parse_version, RustcVersion}; +use rustc_attr_parsing::{RustcVersion, parse_version}; use rustc_session::Session; use rustc_span::{Symbol, sym}; use serde::Deserialize; @@ -19,11 +19,12 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY } - 1,82,0 { IS_NONE_OR, REPEAT_N } - 1,81,0 { LINT_REASONS_STABILIZATION } - 1,80,0 { BOX_INTO_ITER} + 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP } + 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE } + 1,80,0 { BOX_INTO_ITER } 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } + 1,74,0 { REPR_RUST } 1,73,0 { MANUAL_DIV_CEIL } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index bb40a9430a7af..8cb8cd5901400 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -23,7 +23,6 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"]; pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"]; -pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"]; pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty/mod.rs similarity index 99% rename from clippy_utils/src/ty.rs rename to clippy_utils/src/ty/mod.rs index bc3c3ca5c2179..32e7c2bbf7cb6 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty/mod.rs @@ -171,7 +171,7 @@ pub fn should_call_clone_as_function(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { ) } -/// Returns true if ty has `iter` or `iter_mut` methods +/// If `ty` is known to have a `iter` or `iter_mut` method, returns a symbol representing the type. pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option { // FIXME: instead of this hard-coded list, we should check if `::iter` // exists and has the desired signature. Unfortunately FnCtxt is not exported diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index afceeec22726a..7a3a861a9caeb 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr}; use rustc_hir::{ AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath, - Stmt, UnOp, UnsafeSource, StructTailExpr, + Stmt, StructTailExpr, UnOp, UnsafeSource, }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 8c62dd3ed3859..03e2a24f6f989 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -17,7 +17,8 @@ #![allow( clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args, - clippy::module_name_repetitions + clippy::module_name_repetitions, + clippy::literal_string_with_formatting_args )] mod config; diff --git a/rust-toolchain b/rust-toolchain index fb159ca2ae038..1000d90f52a52 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2024-11-28" +channel = "nightly-2024-12-26" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/driver.rs b/src/driver.rs index 32ee668cda1cb..75ef60a5dc8ac 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -285,7 +285,7 @@ pub fn main() { let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some() && arg_value(&orig_args, "--force-warn", |val| val.contains("clippy::")).is_none(); - // If `--no-deps` is enabled only lint the primary pacakge + // If `--no-deps` is enabled only lint the primary package let relevant_package = !no_deps || env::var("CARGO_PRIMARY_PACKAGE").is_ok(); // Do not run Clippy for Cargo's info queries so that invalid CLIPPY_ARGS are not cached @@ -303,7 +303,7 @@ pub fn main() { .set_using_internal_features(using_internal_features) .run(); } - return Ok(()); + Ok(()) })) } diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed index 98591e15bec47..3bcabb4ab2d36 100644 --- a/tests/ui-internal/interning_defined_symbol.fixed +++ b/tests/ui-internal/interning_defined_symbol.fixed @@ -23,7 +23,7 @@ fn main() { let _ = rustc_span::sym::proc_dash_macro; // interning a keyword - let _ = rustc_span::symbol::kw::SelfLower; + let _ = rustc_span::kw::SelfLower; // Interning a symbol that is not defined let _ = Symbol::intern("xyz123"); diff --git a/tests/ui-internal/interning_defined_symbol.stderr b/tests/ui-internal/interning_defined_symbol.stderr index 6d86768d344e9..c4d0308979f64 100644 --- a/tests/ui-internal/interning_defined_symbol.stderr +++ b/tests/ui-internal/interning_defined_symbol.stderr @@ -27,7 +27,7 @@ error: interning a defined symbol --> tests/ui-internal/interning_defined_symbol.rs:26:13 | LL | let _ = Symbol::intern("self"); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::kw::SelfLower` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::kw::SelfLower` error: aborting due to 4 previous errors diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index 8e7f020c1f659..3d9deb705ace8 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -14,8 +14,8 @@ use rustc_span::symbol::{Ident, Symbol}; fn main() { Symbol::intern("foo") == rustc_span::sym::clippy; - Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower; - Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper; + Symbol::intern("foo") == rustc_span::kw::SelfLower; + Symbol::intern("foo") != rustc_span::kw::SelfUpper; Ident::empty().name == rustc_span::sym::clippy; rustc_span::sym::clippy == Ident::empty().name; } diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr index 668c11722f91c..1742603eff6d9 100644 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ b/tests/ui-internal/unnecessary_symbol_str.stderr @@ -15,13 +15,13 @@ error: unnecessary `Symbol` to string conversion --> tests/ui-internal/unnecessary_symbol_str.rs:17:5 | LL | Symbol::intern("foo").to_string() == "self"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::kw::SelfLower` error: unnecessary `Symbol` to string conversion --> tests/ui-internal/unnecessary_symbol_str.rs:18:5 | LL | Symbol::intern("foo").to_ident_string() != "Self"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::kw::SelfUpper` error: unnecessary `Symbol` to string conversion --> tests/ui-internal/unnecessary_symbol_str.rs:19:5 diff --git a/tests/ui-toml/indexing_slicing/clippy.toml b/tests/ui-toml/indexing_slicing/clippy.toml new file mode 100644 index 0000000000000..7e83868332f1c --- /dev/null +++ b/tests/ui-toml/indexing_slicing/clippy.toml @@ -0,0 +1 @@ +allow-indexing-slicing-in-tests = true diff --git a/tests/ui-toml/indexing_slicing/indexing_slicing.rs b/tests/ui-toml/indexing_slicing/indexing_slicing.rs new file mode 100644 index 0000000000000..0a0da88ea1fad --- /dev/null +++ b/tests/ui-toml/indexing_slicing/indexing_slicing.rs @@ -0,0 +1,19 @@ +//@compile-flags: --test +#![warn(clippy::indexing_slicing)] +#![allow(clippy::no_effect)] + +fn main() { + let x = [1, 2, 3, 4]; + let index: usize = 1; + &x[index..]; +} + +#[cfg(test)] +mod tests { + #[test] + fn test_fn() { + let x = [1, 2, 3, 4]; + let index: usize = 1; + &x[index..]; + } +} diff --git a/tests/ui-toml/indexing_slicing/indexing_slicing.stderr b/tests/ui-toml/indexing_slicing/indexing_slicing.stderr new file mode 100644 index 0000000000000..5a4de8337b468 --- /dev/null +++ b/tests/ui-toml/indexing_slicing/indexing_slicing.stderr @@ -0,0 +1,12 @@ +error: slicing may panic + --> tests/ui-toml/indexing_slicing/indexing_slicing.rs:8:6 + | +LL | &x[index..]; + | ^^^^^^^^^^ + | + = help: consider using `.get(n..)` or .get_mut(n..)` instead + = note: `-D clippy::indexing-slicing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/large_include_file/large_include_file.rs b/tests/ui-toml/large_include_file/large_include_file.rs index 8a6dd36501cff..184c6d17ba41e 100644 --- a/tests/ui-toml/large_include_file/large_include_file.rs +++ b/tests/ui-toml/large_include_file/large_include_file.rs @@ -1,4 +1,5 @@ #![warn(clippy::large_include_file)] +#![allow(clippy::literal_string_with_formatting_args)] // Good const GOOD_INCLUDE_BYTES: &[u8; 68] = include_bytes!("../../ui/author.rs"); diff --git a/tests/ui-toml/large_include_file/large_include_file.stderr b/tests/ui-toml/large_include_file/large_include_file.stderr index 9e1494a47bbaa..82b926cc53ba2 100644 --- a/tests/ui-toml/large_include_file/large_include_file.stderr +++ b/tests/ui-toml/large_include_file/large_include_file.stderr @@ -1,5 +1,5 @@ error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:13:43 + --> tests/ui-toml/large_include_file/large_include_file.rs:14:43 | LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]` error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:15:35 + --> tests/ui-toml/large_include_file/large_include_file.rs:16:35 | LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); = note: the configuration allows a maximum size of 600 bytes error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:18:1 + --> tests/ui-toml/large_include_file/large_include_file.rs:19:1 | LL | #[doc = include_str!("too_big.txt")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed new file mode 100644 index 0000000000000..36540bf1dcf73 --- /dev/null +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed @@ -0,0 +1,24 @@ +#![deny(clippy::index_refutable_slice)] + +fn below_limit() { + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some([_, _, _, _, _, _, _, slice_7, ..]) = slice { + //~^ ERROR: binding can be a slice pattern + // This would usually not be linted but is included now due to the + // index limit in the config file + println!("{}", slice_7); + } +} + +fn above_limit() { + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some(slice) = slice { + // This will not be linted as 8 is above the limit + println!("{}", slice[8]); + } +} + +fn main() { + below_limit(); + above_limit(); +} diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs index e64c8ff329001..da76bb20fd961 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs @@ -1,7 +1,5 @@ #![deny(clippy::index_refutable_slice)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - fn below_limit() { let slice: Option<&[u32]> = Some(&[1, 2, 3]); if let Some(slice) = slice { diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr index 3ea600c7d7b0c..022deb330e6e3 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:7:17 + --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:5:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -9,14 +9,14 @@ note: the lint level is defined here | LL | #![deny(clippy::index_refutable_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([_, _, _, _, _, _, _, slice_7, ..]) = slice { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([_, _, _, _, _, _, _, slice_7, ..]) = slice { +LL | +LL | // This would usually not be linted but is included now due to the +LL | // index limit in the config file +LL ~ println!("{}", slice_7); | -LL | println!("{}", slice_7); - | ~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6fa583fc0417a..200129da25f50 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -6,6 +6,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-comparison-to-zero allow-dbg-in-tests allow-expect-in-tests + allow-indexing-slicing-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests @@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-comparison-to-zero allow-dbg-in-tests allow-expect-in-tests + allow-indexing-slicing-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests @@ -180,6 +182,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-comparison-to-zero allow-dbg-in-tests allow-expect-in-tests + allow-indexing-slicing-in-tests allow-mixed-uninlined-format-args allow-one-hash-in-raw-strings allow-panic-in-tests diff --git a/tests/ui/as_pointer_underscore.fixed b/tests/ui/as_pointer_underscore.fixed new file mode 100644 index 0000000000000..db06486ecb048 --- /dev/null +++ b/tests/ui/as_pointer_underscore.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::as_pointer_underscore)] +#![crate_type = "lib"] +#![no_std] + +struct S; + +fn f(s: &S) -> usize { + &s as *const &S as usize + //~^ ERROR: using inferred pointer cast +} + +fn g(s: &mut S) -> usize { + s as *mut S as usize + //~^ ERROR: using inferred pointer cast +} diff --git a/tests/ui/as_pointer_underscore.rs b/tests/ui/as_pointer_underscore.rs new file mode 100644 index 0000000000000..955c702ccc998 --- /dev/null +++ b/tests/ui/as_pointer_underscore.rs @@ -0,0 +1,15 @@ +#![warn(clippy::as_pointer_underscore)] +#![crate_type = "lib"] +#![no_std] + +struct S; + +fn f(s: &S) -> usize { + &s as *const _ as usize + //~^ ERROR: using inferred pointer cast +} + +fn g(s: &mut S) -> usize { + s as *mut _ as usize + //~^ ERROR: using inferred pointer cast +} diff --git a/tests/ui/as_pointer_underscore.stderr b/tests/ui/as_pointer_underscore.stderr new file mode 100644 index 0000000000000..270056f36454e --- /dev/null +++ b/tests/ui/as_pointer_underscore.stderr @@ -0,0 +1,17 @@ +error: using inferred pointer cast + --> tests/ui/as_pointer_underscore.rs:8:11 + | +LL | &s as *const _ as usize + | ^^^^^^^^ help: use explicit type: `*const &S` + | + = note: `-D clippy::as-pointer-underscore` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::as_pointer_underscore)]` + +error: using inferred pointer cast + --> tests/ui/as_pointer_underscore.rs:13:10 + | +LL | s as *mut _ as usize + | ^^^^^^ help: use explicit type: `*mut S` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index fbf84337382e1..1815dd58f5107 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -2,6 +2,7 @@ #![allow(incomplete_features)] #![allow(clippy::field_reassign_with_default)] #![allow(clippy::eq_op)] +#![allow(clippy::literal_string_with_formatting_args)] extern crate proc_macro; diff --git a/tests/ui/borrow_and_ref_as_ptr.fixed b/tests/ui/borrow_and_ref_as_ptr.fixed new file mode 100644 index 0000000000000..2950b158deb64 --- /dev/null +++ b/tests/ui/borrow_and_ref_as_ptr.fixed @@ -0,0 +1,11 @@ +// Make sure that `ref_as_ptr` is not emitted when `borrow_as_ptr` is. + +#![warn(clippy::ref_as_ptr, clippy::borrow_as_ptr)] + +fn f(_: T) {} + +fn main() { + let mut val = 0; + f(&raw const val); + f(&raw mut val); +} diff --git a/tests/ui/borrow_and_ref_as_ptr.rs b/tests/ui/borrow_and_ref_as_ptr.rs new file mode 100644 index 0000000000000..19eb8f2923374 --- /dev/null +++ b/tests/ui/borrow_and_ref_as_ptr.rs @@ -0,0 +1,11 @@ +// Make sure that `ref_as_ptr` is not emitted when `borrow_as_ptr` is. + +#![warn(clippy::ref_as_ptr, clippy::borrow_as_ptr)] + +fn f(_: T) {} + +fn main() { + let mut val = 0; + f(&val as *const _); + f(&mut val as *mut i32); +} diff --git a/tests/ui/borrow_and_ref_as_ptr.stderr b/tests/ui/borrow_and_ref_as_ptr.stderr new file mode 100644 index 0000000000000..82a27af303c21 --- /dev/null +++ b/tests/ui/borrow_and_ref_as_ptr.stderr @@ -0,0 +1,17 @@ +error: borrow as raw pointer + --> tests/ui/borrow_and_ref_as_ptr.rs:9:7 + | +LL | f(&val as *const _); + | ^^^^^^^^^^^^^^^^ help: try: `&raw const val` + | + = note: `-D clippy::borrow-as-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` + +error: borrow as raw pointer + --> tests/ui/borrow_and_ref_as_ptr.rs:10:7 + | +LL | f(&mut val as *mut i32); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut val` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/borrow_as_ptr_raw_ref.fixed b/tests/ui/borrow_as_ptr_raw_ref.fixed new file mode 100644 index 0000000000000..d6842e60a3e9f --- /dev/null +++ b/tests/ui/borrow_as_ptr_raw_ref.fixed @@ -0,0 +1,19 @@ +#![warn(clippy::borrow_as_ptr)] +#![allow(clippy::useless_vec)] + +fn a() -> i32 { + 0 +} + +#[clippy::msrv = "1.82"] +fn main() { + let val = 1; + let _p = &raw const val; + let _p = &0 as *const i32; + let _p = &a() as *const i32; + let vec = vec![1]; + let _p = &vec.len() as *const usize; + + let mut val_mut = 1; + let _p_mut = &raw mut val_mut; +} diff --git a/tests/ui/borrow_as_ptr_raw_ref.rs b/tests/ui/borrow_as_ptr_raw_ref.rs new file mode 100644 index 0000000000000..3c9daed18f15a --- /dev/null +++ b/tests/ui/borrow_as_ptr_raw_ref.rs @@ -0,0 +1,19 @@ +#![warn(clippy::borrow_as_ptr)] +#![allow(clippy::useless_vec)] + +fn a() -> i32 { + 0 +} + +#[clippy::msrv = "1.82"] +fn main() { + let val = 1; + let _p = &val as *const i32; + let _p = &0 as *const i32; + let _p = &a() as *const i32; + let vec = vec![1]; + let _p = &vec.len() as *const usize; + + let mut val_mut = 1; + let _p_mut = &mut val_mut as *mut i32; +} diff --git a/tests/ui/borrow_as_ptr_raw_ref.stderr b/tests/ui/borrow_as_ptr_raw_ref.stderr new file mode 100644 index 0000000000000..5611fcae8d4b1 --- /dev/null +++ b/tests/ui/borrow_as_ptr_raw_ref.stderr @@ -0,0 +1,17 @@ +error: borrow as raw pointer + --> tests/ui/borrow_as_ptr_raw_ref.rs:11:14 + | +LL | let _p = &val as *const i32; + | ^^^^^^^^^^^^^^^^^^ help: try: `&raw const val` + | + = note: `-D clippy::borrow-as-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` + +error: borrow as raw pointer + --> tests/ui/borrow_as_ptr_raw_ref.rs:18:18 + | +LL | let _p_mut = &mut val_mut as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut val_mut` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/comparison_chain.rs b/tests/ui/comparison_chain.rs index 266cee4c33890..cab460d100dda 100644 --- a/tests/ui/comparison_chain.rs +++ b/tests/ui/comparison_chain.rs @@ -1,3 +1,4 @@ +//@no-rustfix #![allow(dead_code)] #![warn(clippy::comparison_chain)] @@ -238,4 +239,16 @@ const fn sign_i8(n: i8) -> Sign { } } +fn needs_parens() -> &'static str { + let (x, y) = (1, 2); + if x + 1 > y * 2 { + //~^ ERROR: `if` chain can be rewritten with `match` + "aa" + } else if x + 1 < y * 2 { + "bb" + } else { + "cc" + } +} + fn main() {} diff --git a/tests/ui/comparison_chain.stderr b/tests/ui/comparison_chain.stderr index 96d8d819e6a55..814004e3d4b16 100644 --- a/tests/ui/comparison_chain.stderr +++ b/tests/ui/comparison_chain.stderr @@ -1,5 +1,5 @@ error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:14:5 + --> tests/ui/comparison_chain.rs:15:5 | LL | / if x > y { LL | | @@ -7,14 +7,13 @@ LL | | a() LL | | } else if x < y { LL | | b() LL | | } - | |_____^ + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` | - = help: consider rewriting the `if` chain to use `cmp` and `match` = note: `-D clippy::comparison-chain` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:28:5 + --> tests/ui/comparison_chain.rs:29:5 | LL | / if x > y { LL | | @@ -23,12 +22,10 @@ LL | | } else if x < y { ... | LL | | c() LL | | } - | |_____^ - | - = help: consider rewriting the `if` chain to use `cmp` and `match` + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:37:5 + --> tests/ui/comparison_chain.rs:38:5 | LL | / if x > y { LL | | @@ -37,12 +34,10 @@ LL | | } else if y > x { ... | LL | | c() LL | | } - | |_____^ - | - = help: consider rewriting the `if` chain to use `cmp` and `match` + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:46:5 + --> tests/ui/comparison_chain.rs:47:5 | LL | / if x > 1 { LL | | @@ -51,12 +46,10 @@ LL | | } else if x < 1 { ... | LL | | c() LL | | } - | |_____^ - | - = help: consider rewriting the `if` chain to use `cmp` and `match` + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&1) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:121:5 + --> tests/ui/comparison_chain.rs:122:5 | LL | / if x > y { LL | | @@ -64,12 +57,10 @@ LL | | a() LL | | } else if x < y { LL | | b() LL | | } - | |_____^ - | - = help: consider rewriting the `if` chain to use `cmp` and `match` + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:128:5 + --> tests/ui/comparison_chain.rs:129:5 | LL | / if x > y { LL | | @@ -78,12 +69,10 @@ LL | | } else if x < y { ... | LL | | c() LL | | } - | |_____^ - | - = help: consider rewriting the `if` chain to use `cmp` and `match` + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:137:5 + --> tests/ui/comparison_chain.rs:138:5 | LL | / if x > y { LL | | @@ -92,9 +81,19 @@ LL | | } else if y > x { ... | LL | | c() LL | | } - | |_____^ + | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` + +error: `if` chain can be rewritten with `match` + --> tests/ui/comparison_chain.rs:244:5 | - = help: consider rewriting the `if` chain to use `cmp` and `match` +LL | / if x + 1 > y * 2 { +LL | | +LL | | "aa" +LL | | } else if x + 1 < y * 2 { +... | +LL | | "cc" +LL | | } + | |_____^ help: consider rewriting the `if` chain with `match`: `match (x + 1).cmp(&(y * 2)) {...}` -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/default_union_representation.rs b/tests/ui/default_union_representation.rs index 41308b077bac6..ba63cde2fa9d4 100644 --- a/tests/ui/default_union_representation.rs +++ b/tests/ui/default_union_representation.rs @@ -1,5 +1,6 @@ #![feature(transparent_unions)] #![warn(clippy::default_union_representation)] +#![allow(clippy::repr_packed_without_abi)] union NoAttribute { //~^ ERROR: this union has the default representation diff --git a/tests/ui/default_union_representation.stderr b/tests/ui/default_union_representation.stderr index c7ef70a0b8e7b..d558a3e8de1b9 100644 --- a/tests/ui/default_union_representation.stderr +++ b/tests/ui/default_union_representation.stderr @@ -1,5 +1,5 @@ error: this union has the default representation - --> tests/ui/default_union_representation.rs:4:1 + --> tests/ui/default_union_representation.rs:5:1 | LL | / union NoAttribute { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::default_union_representation)]` error: this union has the default representation - --> tests/ui/default_union_representation.rs:17:1 + --> tests/ui/default_union_representation.rs:18:1 | LL | / union ReprPacked { LL | | @@ -25,7 +25,7 @@ LL | | } = help: consider annotating `ReprPacked` with `#[repr(C)]` to explicitly specify memory layout error: this union has the default representation - --> tests/ui/default_union_representation.rs:36:1 + --> tests/ui/default_union_representation.rs:37:1 | LL | / union ReprAlign { LL | | @@ -37,7 +37,7 @@ LL | | } = help: consider annotating `ReprAlign` with `#[repr(C)]` to explicitly specify memory layout error: this union has the default representation - --> tests/ui/default_union_representation.rs:57:1 + --> tests/ui/default_union_representation.rs:58:1 | LL | / union ZSTAndTwoFields { LL | | diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index b06dd78608fdc..d03cc01a08b0b 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -2,6 +2,7 @@ clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::needless_lifetimes, + clippy::repr_packed_without_abi, dead_code )] #![warn(clippy::expl_impl_clone_on_copy)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index 0eb4b3c1adaa6..d70a59855229d 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -1,5 +1,5 @@ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:13:1 + --> tests/ui/derive.rs:14:1 | LL | / impl Clone for Qux { LL | | @@ -10,7 +10,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:13:1 + --> tests/ui/derive.rs:14:1 | LL | / impl Clone for Qux { LL | | @@ -23,7 +23,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]` error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:38:1 + --> tests/ui/derive.rs:39:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | @@ -34,7 +34,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:38:1 + --> tests/ui/derive.rs:39:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | @@ -45,7 +45,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:50:1 + --> tests/ui/derive.rs:51:1 | LL | / impl Clone for BigArray { LL | | @@ -56,7 +56,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:50:1 + --> tests/ui/derive.rs:51:1 | LL | / impl Clone for BigArray { LL | | @@ -67,7 +67,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:62:1 + --> tests/ui/derive.rs:63:1 | LL | / impl Clone for FnPtr { LL | | @@ -78,7 +78,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:62:1 + --> tests/ui/derive.rs:63:1 | LL | / impl Clone for FnPtr { LL | | @@ -89,7 +89,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:83:1 + --> tests/ui/derive.rs:84:1 | LL | / impl Clone for Generic2 { LL | | @@ -100,7 +100,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:83:1 + --> tests/ui/derive.rs:84:1 | LL | / impl Clone for Generic2 { LL | | diff --git a/tests/ui/doc/doc_lazy_list.fixed b/tests/ui/doc/doc_lazy_list.fixed index da537518a2b53..0822cc7c6350a 100644 --- a/tests/ui/doc/doc_lazy_list.fixed +++ b/tests/ui/doc/doc_lazy_list.fixed @@ -75,3 +75,9 @@ fn seven() {} /// ] //~^ ERROR: doc list item without indentation fn eight() {} + +#[rustfmt::skip] +// https://github.com/rust-lang/rust-clippy/issues/13705 +/// - \[text in square brackets\] with a long following description +/// that goes over multiple lines +pub fn backslash_escaped_square_braces() {} diff --git a/tests/ui/doc/doc_lazy_list.rs b/tests/ui/doc/doc_lazy_list.rs index 3cc18e35780a2..068de140e00a0 100644 --- a/tests/ui/doc/doc_lazy_list.rs +++ b/tests/ui/doc/doc_lazy_list.rs @@ -75,3 +75,9 @@ fn seven() {} /// ] //~^ ERROR: doc list item without indentation fn eight() {} + +#[rustfmt::skip] +// https://github.com/rust-lang/rust-clippy/issues/13705 +/// - \[text in square brackets\] with a long following description +/// that goes over multiple lines +pub fn backslash_escaped_square_braces() {} diff --git a/tests/ui/doc/doc_nested_refdef_blockquote.fixed b/tests/ui/doc/doc_nested_refdef_blockquote.fixed new file mode 100644 index 0000000000000..8939a03d2e3ea --- /dev/null +++ b/tests/ui/doc/doc_nested_refdef_blockquote.fixed @@ -0,0 +1,133 @@ +// https://github.com/rust-lang/rust/issues/133150 +#![warn(clippy::doc_nested_refdefs)] +#[rustfmt::skip] +/// > [link][]: def +//~^ ERROR: link reference defined in quote +/// +/// > [link][]: def (title) +//~^ ERROR: link reference defined in quote +/// +/// > [link][]: def "title" +//~^ ERROR: link reference defined in quote +/// +/// > [link]: not def +/// +/// > [link][]: notdef +/// +/// > [link]\: notdef +pub struct Empty; + +#[rustfmt::skip] +/// > [link][]: def +//~^ ERROR: link reference defined in quote +/// > inner text +/// +/// > [link][]: def (title) +//~^ ERROR: link reference defined in quote +/// > inner text +/// +/// > [link][]: def "title" +//~^ ERROR: link reference defined in quote +/// > inner text +/// +/// > [link]: not def +/// > inner text +/// +/// > [link][]: notdef +/// > inner text +/// +/// > [link]\: notdef +/// > inner text +pub struct NotEmpty; + +#[rustfmt::skip] +/// > [link][]: def +//~^ ERROR: link reference defined in quote +/// > +/// > inner text +/// +/// > [link][]: def (title) +//~^ ERROR: link reference defined in quote +/// > +/// > inner text +/// +/// > [link][]: def "title" +//~^ ERROR: link reference defined in quote +/// > +/// > inner text +/// +/// > [link]: not def +/// > +/// > inner text +/// +/// > [link][]: notdef +/// > +/// > inner text +/// +/// > [link]\: notdef +/// > +/// > inner text +pub struct NotEmptyLoose; + +#[rustfmt::skip] +/// > first lines +/// > [link]: def +/// +/// > first lines +/// > [link]: def (title) +/// +/// > firs lines +/// > [link]: def "title" +/// +/// > firs lines +/// > [link]: not def +/// +/// > first lines +/// > [link][]: notdef +/// +/// > first lines +/// > [link]\: notdef +pub struct NotAtStartTight; + +#[rustfmt::skip] +/// > first lines +/// > +/// > [link]: def +/// +/// > first lines +/// > +/// > [link]: def (title) +/// +/// > firs lines +/// > +/// > [link]: def "title" +/// +/// > firs lines +/// > +/// > [link]: not def +/// +/// > first lines +/// > +/// > [link][]: notdef +/// +/// > first lines +/// > +/// > [link]\: notdef +pub struct NotAtStartLoose; + +#[rustfmt::skip] +/// > - [link][]: def +//~^ ERROR: link reference defined in list item +/// > +/// > - [link][]: def (title) +//~^ ERROR: link reference defined in list item +/// > +/// > - [link][]: def "title" +//~^ ERROR: link reference defined in list item +/// > +/// > - [link]: not def +/// > +/// > - [link][]: notdef +/// > +/// > - [link]\: notdef +pub struct ListNested; diff --git a/tests/ui/doc/doc_nested_refdef_blockquote.rs b/tests/ui/doc/doc_nested_refdef_blockquote.rs new file mode 100644 index 0000000000000..f861242384bab --- /dev/null +++ b/tests/ui/doc/doc_nested_refdef_blockquote.rs @@ -0,0 +1,133 @@ +// https://github.com/rust-lang/rust/issues/133150 +#![warn(clippy::doc_nested_refdefs)] +#[rustfmt::skip] +/// > [link]: def +//~^ ERROR: link reference defined in quote +/// +/// > [link]: def (title) +//~^ ERROR: link reference defined in quote +/// +/// > [link]: def "title" +//~^ ERROR: link reference defined in quote +/// +/// > [link]: not def +/// +/// > [link][]: notdef +/// +/// > [link]\: notdef +pub struct Empty; + +#[rustfmt::skip] +/// > [link]: def +//~^ ERROR: link reference defined in quote +/// > inner text +/// +/// > [link]: def (title) +//~^ ERROR: link reference defined in quote +/// > inner text +/// +/// > [link]: def "title" +//~^ ERROR: link reference defined in quote +/// > inner text +/// +/// > [link]: not def +/// > inner text +/// +/// > [link][]: notdef +/// > inner text +/// +/// > [link]\: notdef +/// > inner text +pub struct NotEmpty; + +#[rustfmt::skip] +/// > [link]: def +//~^ ERROR: link reference defined in quote +/// > +/// > inner text +/// +/// > [link]: def (title) +//~^ ERROR: link reference defined in quote +/// > +/// > inner text +/// +/// > [link]: def "title" +//~^ ERROR: link reference defined in quote +/// > +/// > inner text +/// +/// > [link]: not def +/// > +/// > inner text +/// +/// > [link][]: notdef +/// > +/// > inner text +/// +/// > [link]\: notdef +/// > +/// > inner text +pub struct NotEmptyLoose; + +#[rustfmt::skip] +/// > first lines +/// > [link]: def +/// +/// > first lines +/// > [link]: def (title) +/// +/// > firs lines +/// > [link]: def "title" +/// +/// > firs lines +/// > [link]: not def +/// +/// > first lines +/// > [link][]: notdef +/// +/// > first lines +/// > [link]\: notdef +pub struct NotAtStartTight; + +#[rustfmt::skip] +/// > first lines +/// > +/// > [link]: def +/// +/// > first lines +/// > +/// > [link]: def (title) +/// +/// > firs lines +/// > +/// > [link]: def "title" +/// +/// > firs lines +/// > +/// > [link]: not def +/// +/// > first lines +/// > +/// > [link][]: notdef +/// +/// > first lines +/// > +/// > [link]\: notdef +pub struct NotAtStartLoose; + +#[rustfmt::skip] +/// > - [link]: def +//~^ ERROR: link reference defined in list item +/// > +/// > - [link]: def (title) +//~^ ERROR: link reference defined in list item +/// > +/// > - [link]: def "title" +//~^ ERROR: link reference defined in list item +/// > +/// > - [link]: not def +/// > +/// > - [link][]: notdef +/// > +/// > - [link]\: notdef +pub struct ListNested; diff --git a/tests/ui/doc/doc_nested_refdef_blockquote.stderr b/tests/ui/doc/doc_nested_refdef_blockquote.stderr new file mode 100644 index 0000000000000..448659b894103 --- /dev/null +++ b/tests/ui/doc/doc_nested_refdef_blockquote.stderr @@ -0,0 +1,148 @@ +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:4:7 + | +LL | /// > [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation + = note: `-D clippy::doc-nested-refdefs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_nested_refdefs)]` +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:7:7 + | +LL | /// > [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def (title) + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:10:7 + | +LL | /// > [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def "title" + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:21:7 + | +LL | /// > [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:25:7 + | +LL | /// > [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def (title) + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:29:7 + | +LL | /// > [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def "title" + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:44:7 + | +LL | /// > [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:49:7 + | +LL | /// > [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def (title) + | ++ + +error: link reference defined in quote + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:54:7 + | +LL | /// > [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > [link][]: def "title" + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:119:9 + | +LL | /// > - [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > - [link][]: def + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:122:9 + | +LL | /// > - [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > - [link][]: def (title) + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_blockquote.rs:125:9 + | +LL | /// > - [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// > - [link][]: def "title" + | ++ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/doc/doc_nested_refdef_list_item.fixed b/tests/ui/doc/doc_nested_refdef_list_item.fixed new file mode 100644 index 0000000000000..fcfcfcc40736a --- /dev/null +++ b/tests/ui/doc/doc_nested_refdef_list_item.fixed @@ -0,0 +1,71 @@ +// https://github.com/rust-lang/rust/issues/133150 +#![warn(clippy::doc_nested_refdefs)] +#[rustfmt::skip] +/// - [link][]: def +//~^ ERROR: link reference defined in list item +/// +/// - [link][]: def (title) +//~^ ERROR: link reference defined in list item +/// +/// - [link][]: def "title" +//~^ ERROR: link reference defined in list item +/// +/// - [link]: not def +/// +/// - [link][]: notdef +/// +/// - [link]\: notdef +pub struct Empty; + +#[rustfmt::skip] +/// - [link][]: def +//~^ ERROR: link reference defined in list item +/// - [link][]: def (title) +//~^ ERROR: link reference defined in list item +/// - [link][]: def "title" +//~^ ERROR: link reference defined in list item +/// - [link]: not def +/// - [link][]: notdef +/// - [link]\: notdef +pub struct EmptyTight; + +#[rustfmt::skip] +/// - [link][]: def +//~^ ERROR: link reference defined in list item +/// inner text +/// +/// - [link][]: def (title) +//~^ ERROR: link reference defined in list item +/// inner text +/// +/// - [link][]: def "title" +//~^ ERROR: link reference defined in list item +/// inner text +/// +/// - [link]: not def +/// inner text +/// +/// - [link][]: notdef +/// inner text +/// +/// - [link]\: notdef +/// inner text +pub struct NotEmpty; + +#[rustfmt::skip] +/// - [link][]: def +//~^ ERROR: link reference defined in list item +/// inner text +/// - [link][]: def (title) +//~^ ERROR: link reference defined in list item +/// inner text +/// - [link][]: def "title" +//~^ ERROR: link reference defined in list item +/// inner text +/// - [link]: not def +/// inner text +/// - [link][]: notdef +/// inner text +/// - [link]\: notdef +/// inner text +pub struct NotEmptyTight; diff --git a/tests/ui/doc/doc_nested_refdef_list_item.rs b/tests/ui/doc/doc_nested_refdef_list_item.rs new file mode 100644 index 0000000000000..53368de4616d8 --- /dev/null +++ b/tests/ui/doc/doc_nested_refdef_list_item.rs @@ -0,0 +1,71 @@ +// https://github.com/rust-lang/rust/issues/133150 +#![warn(clippy::doc_nested_refdefs)] +#[rustfmt::skip] +/// - [link]: def +//~^ ERROR: link reference defined in list item +/// +/// - [link]: def (title) +//~^ ERROR: link reference defined in list item +/// +/// - [link]: def "title" +//~^ ERROR: link reference defined in list item +/// +/// - [link]: not def +/// +/// - [link][]: notdef +/// +/// - [link]\: notdef +pub struct Empty; + +#[rustfmt::skip] +/// - [link]: def +//~^ ERROR: link reference defined in list item +/// - [link]: def (title) +//~^ ERROR: link reference defined in list item +/// - [link]: def "title" +//~^ ERROR: link reference defined in list item +/// - [link]: not def +/// - [link][]: notdef +/// - [link]\: notdef +pub struct EmptyTight; + +#[rustfmt::skip] +/// - [link]: def +//~^ ERROR: link reference defined in list item +/// inner text +/// +/// - [link]: def (title) +//~^ ERROR: link reference defined in list item +/// inner text +/// +/// - [link]: def "title" +//~^ ERROR: link reference defined in list item +/// inner text +/// +/// - [link]: not def +/// inner text +/// +/// - [link][]: notdef +/// inner text +/// +/// - [link]\: notdef +/// inner text +pub struct NotEmpty; + +#[rustfmt::skip] +/// - [link]: def +//~^ ERROR: link reference defined in list item +/// inner text +/// - [link]: def (title) +//~^ ERROR: link reference defined in list item +/// inner text +/// - [link]: def "title" +//~^ ERROR: link reference defined in list item +/// inner text +/// - [link]: not def +/// inner text +/// - [link][]: notdef +/// inner text +/// - [link]\: notdef +/// inner text +pub struct NotEmptyTight; diff --git a/tests/ui/doc/doc_nested_refdef_list_item.stderr b/tests/ui/doc/doc_nested_refdef_list_item.stderr new file mode 100644 index 0000000000000..27314c7e968dd --- /dev/null +++ b/tests/ui/doc/doc_nested_refdef_list_item.stderr @@ -0,0 +1,148 @@ +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:4:7 + | +LL | /// - [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation + = note: `-D clippy::doc-nested-refdefs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_nested_refdefs)]` +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:7:7 + | +LL | /// - [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def (title) + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:10:7 + | +LL | /// - [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def "title" + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:21:7 + | +LL | /// - [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:23:7 + | +LL | /// - [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def (title) + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:25:7 + | +LL | /// - [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def "title" + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:33:7 + | +LL | /// - [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:37:7 + | +LL | /// - [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def (title) + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:41:7 + | +LL | /// - [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def "title" + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:56:7 + | +LL | /// - [link]: def + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:59:7 + | +LL | /// - [link]: def (title) + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def (title) + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:62:7 + | +LL | /// - [link]: def "title" + | ^^^^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [link][]: def "title" + | ++ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed index f3f6848e5f92f..fdd020fcd7738 100644 --- a/tests/ui/filter_map_identity.fixed +++ b/tests/ui/filter_map_identity.fixed @@ -81,3 +81,8 @@ fn main() { //~^ ERROR: use of } } + +fn issue12653() -> impl Iterator { + [].into_iter().filter_map(|x| x) + // No lint +} diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs index b9aa9c05be89c..a626de9f5bbd8 100644 --- a/tests/ui/filter_map_identity.rs +++ b/tests/ui/filter_map_identity.rs @@ -81,3 +81,8 @@ fn main() { //~^ ERROR: use of } } + +fn issue12653() -> impl Iterator { + [].into_iter().filter_map(|x| x) + // No lint +} diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 2b32fdeae2b59..3dc8eb79ba284 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -6,7 +6,8 @@ clippy::needless_borrow, clippy::uninlined_format_args, clippy::needless_raw_string_hashes, - clippy::useless_vec + clippy::useless_vec, + clippy::literal_string_with_formatting_args )] struct Foo(pub String); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index bad192067e933..eaf33c2a6c924 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -6,7 +6,8 @@ clippy::needless_borrow, clippy::uninlined_format_args, clippy::needless_raw_string_hashes, - clippy::useless_vec + clippy::useless_vec, + clippy::literal_string_with_formatting_args )] struct Foo(pub String); diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index faa80b48000f9..1368c8cd77e01 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -1,5 +1,5 @@ error: useless use of `format!` - --> tests/ui/format.rs:19:5 + --> tests/ui/format.rs:20:5 | LL | format!("foo"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` @@ -8,19 +8,19 @@ LL | format!("foo"); = help: to override `-D warnings` add `#[allow(clippy::useless_format)]` error: useless use of `format!` - --> tests/ui/format.rs:20:5 + --> tests/ui/format.rs:21:5 | LL | format!("{{}}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` - --> tests/ui/format.rs:21:5 + --> tests/ui/format.rs:22:5 | LL | format!("{{}} abc {{}}"); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` - --> tests/ui/format.rs:22:5 + --> tests/ui/format.rs:23:5 | LL | / format!( LL | | r##"foo {{}} @@ -35,67 +35,67 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> tests/ui/format.rs:27:13 + --> tests/ui/format.rs:28:13 | LL | let _ = format!(""); | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` error: useless use of `format!` - --> tests/ui/format.rs:29:5 + --> tests/ui/format.rs:30:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> tests/ui/format.rs:37:5 + --> tests/ui/format.rs:38:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:67:5 + --> tests/ui/format.rs:68:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:69:5 + --> tests/ui/format.rs:70:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> tests/ui/format.rs:73:18 + --> tests/ui/format.rs:74:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> tests/ui/format.rs:77:22 + --> tests/ui/format.rs:78:22 | LL | let _s: String = format!("{}", &*v.join("\n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("\n")).to_string()` error: useless use of `format!` - --> tests/ui/format.rs:83:13 + --> tests/ui/format.rs:84:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:85:13 + --> tests/ui/format.rs:86:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:89:13 + --> tests/ui/format.rs:90:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:91:13 + --> tests/ui/format.rs:92:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` diff --git a/tests/ui/if_not_else.fixed b/tests/ui/if_not_else.fixed new file mode 100644 index 0000000000000..11d1e13179c48 --- /dev/null +++ b/tests/ui/if_not_else.fixed @@ -0,0 +1,73 @@ +#![warn(clippy::all)] +#![warn(clippy::if_not_else)] + +fn foo() -> bool { + unimplemented!() +} +fn bla() -> bool { + unimplemented!() +} + +fn main() { + if bla() { + println!("Bunny"); + } else { + //~^ ERROR: unnecessary boolean `not` operation + println!("Bugs"); + } + if 4 == 5 { + println!("Bunny"); + } else { + //~^ ERROR: unnecessary `!=` operation + println!("Bugs"); + } + if !foo() { + println!("Foo"); + } else if !bla() { + println!("Bugs"); + } else { + println!("Bunny"); + } + + if (foo() && bla()) { + println!("both true"); + } else { + #[cfg(not(debug_assertions))] + println!("not debug"); + #[cfg(debug_assertions)] + println!("debug"); + if foo() { + println!("foo"); + } else if bla() { + println!("bla"); + } else { + println!("both false"); + } + } +} + +fn with_comments() { + if foo() { + println!("foo"); /* foo */ + } else { + /* foo is false */ + println!("foo is false"); + } + + if bla() { + println!("bla"); // bla + } else { + // bla is false + println!("bla"); + } +} + +fn with_annotations() { + #[cfg(debug_assertions)] + if foo() { + println!("foo"); /* foo */ + } else { + /* foo is false */ + println!("foo is false"); + } +} diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index fd30e3702a275..fcc67e163e8a4 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -28,4 +28,46 @@ fn main() { } else { println!("Bunny"); } + + if !(foo() && bla()) { + #[cfg(not(debug_assertions))] + println!("not debug"); + #[cfg(debug_assertions)] + println!("debug"); + if foo() { + println!("foo"); + } else if bla() { + println!("bla"); + } else { + println!("both false"); + } + } else { + println!("both true"); + } +} + +fn with_comments() { + if !foo() { + /* foo is false */ + println!("foo is false"); + } else { + println!("foo"); /* foo */ + } + + if !bla() { + // bla is false + println!("bla"); + } else { + println!("bla"); // bla + } +} + +fn with_annotations() { + #[cfg(debug_assertions)] + if !foo() { + /* foo is false */ + println!("foo is false"); + } else { + println!("foo"); /* foo */ + } } diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 92fed7b1bf700..b01cb5af11f74 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -9,9 +9,17 @@ LL | | println!("Bunny"); LL | | } | |_____^ | - = help: remove the `!` and swap the blocks of the `if`/`else` = note: `-D clippy::if-not-else` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::if_not_else)]` +help: try + | +LL ~ if bla() { +LL + println!("Bunny"); +LL + } else { +LL + +LL + println!("Bugs"); +LL + } + | error: unnecessary `!=` operation --> tests/ui/if_not_else.rs:18:5 @@ -24,7 +32,109 @@ LL | | println!("Bunny"); LL | | } | |_____^ | - = help: change to `==` and swap the blocks of the `if`/`else` +help: try + | +LL ~ if 4 == 5 { +LL + println!("Bunny"); +LL + } else { +LL + +LL + println!("Bugs"); +LL + } + | + +error: unnecessary boolean `not` operation + --> tests/ui/if_not_else.rs:32:5 + | +LL | / if !(foo() && bla()) { +LL | | #[cfg(not(debug_assertions))] +LL | | println!("not debug"); +LL | | #[cfg(debug_assertions)] +... | +LL | | println!("both true"); +LL | | } + | |_____^ + | +help: try + | +LL ~ if (foo() && bla()) { +LL + println!("both true"); +LL + } else { +LL + #[cfg(not(debug_assertions))] +LL + println!("not debug"); +LL + #[cfg(debug_assertions)] +LL + println!("debug"); +LL + if foo() { +LL + println!("foo"); +LL + } else if bla() { +LL + println!("bla"); +LL + } else { +LL + println!("both false"); +LL + } +LL + } + | + +error: unnecessary boolean `not` operation + --> tests/ui/if_not_else.rs:50:5 + | +LL | / if !foo() { +LL | | /* foo is false */ +LL | | println!("foo is false"); +LL | | } else { +LL | | println!("foo"); /* foo */ +LL | | } + | |_____^ + | +help: try + | +LL ~ if foo() { +LL + println!("foo"); /* foo */ +LL + } else { +LL + /* foo is false */ +LL + println!("foo is false"); +LL + } + | + +error: unnecessary boolean `not` operation + --> tests/ui/if_not_else.rs:57:5 + | +LL | / if !bla() { +LL | | // bla is false +LL | | println!("bla"); +LL | | } else { +LL | | println!("bla"); // bla +LL | | } + | |_____^ + | +help: try + | +LL ~ if bla() { +LL + println!("bla"); // bla +LL + } else { +LL + // bla is false +LL + println!("bla"); +LL + } + | + +error: unnecessary boolean `not` operation + --> tests/ui/if_not_else.rs:67:5 + | +LL | / if !foo() { +LL | | /* foo is false */ +LL | | println!("foo is false"); +LL | | } else { +LL | | println!("foo"); /* foo */ +LL | | } + | |_____^ + | +help: try + | +LL ~ if foo() { +LL + println!("foo"); /* foo */ +LL + } else { +LL + /* foo is false */ +LL + println!("foo is false"); +LL + } + | -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed new file mode 100644 index 0000000000000..ea8e56e18b085 --- /dev/null +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed @@ -0,0 +1,177 @@ +#![deny(clippy::index_refutable_slice)] +#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)] + +enum SomeEnum { + One(T), + Two(T), + Three(T), + Four(T), +} + +fn lintable_examples() { + // Try with reference + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some([slice_0, ..]) = slice { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + println!("{}", slice_0); + } + + // Try with copy + let slice: Option<[u32; 3]> = Some([1, 2, 3]); + if let Some([slice_0, ..]) = slice { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + println!("{}", slice_0); + } + + // Try with long slice and small indices + let slice: Option<[u32; 9]> = Some([1, 2, 3, 4, 5, 6, 7, 8, 9]); + if let Some([slice_0, _, slice_2, ..]) = slice { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + println!("{}", slice_2); + println!("{}", slice_0); + } + + // Multiple bindings + let slice_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([5, 6, 7]); + if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + println!("{}", slice_0); + } + + // Two lintable slices in one if let + let a_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([9, 5, 1]); + let b_wrapped: Option<[u32; 2]> = Some([4, 6]); + if let (SomeEnum::Three([_, _, a_2, ..]), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~| ERROR: this binding can be a slice pattern to avoid indexing + println!("{} -> {}", a_2, b_1); + } + + // This requires the slice values to be borrowed as the slice values can only be + // borrowed and `String` doesn't implement copy + let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); + if let Some([_, ref slice_1, ..]) = slice { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + println!("{:?}", slice_1); + } + println!("{:?}", slice); + + // This should not suggest using the `ref` keyword as the scrutinee is already + // a reference + let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); + if let Some([slice_0, ..]) = &slice { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + println!("{:?}", slice_0); + } + println!("{:?}", slice); +} + +fn slice_index_above_limit() { + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + + if let Some(slice) = slice { + // Would cause a panic, IDK + println!("{}", slice[7]); + } +} + +fn slice_is_used() { + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some(slice) = slice { + println!("{:?}", slice.len()); + } + + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some(slice) = slice { + println!("{:?}", slice.to_vec()); + } + + let opt: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]); + if let Some(slice) = opt { + if !slice.is_empty() { + println!("first: {}", slice[0]); + } + } +} + +/// The slice is used by an external function and should therefore not be linted +fn check_slice_as_arg() { + fn is_interesting(slice: &[T; 2]) -> bool { + !slice.is_empty() + } + + let slice_wrapped: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]); + if let Some(slice) = &slice_wrapped { + if is_interesting(slice) { + println!("This is interesting {}", slice[0]); + } + } + println!("{:?}", slice_wrapped); +} + +fn check_slice_in_struct() { + #[derive(Debug)] + struct Wrapper<'a> { + inner: Option<&'a [String]>, + is_awesome: bool, + } + + impl<'a> Wrapper<'a> { + fn is_super_awesome(&self) -> bool { + self.is_awesome + } + } + + let inner = &[String::from("New"), String::from("World")]; + let wrap = Wrapper { + inner: Some(inner), + is_awesome: true, + }; + + // Test 1: Field access + if let Some([slice_0, ..]) = wrap.inner { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + if wrap.is_awesome { + println!("This is awesome! {}", slice_0); + } + } + + // Test 2: function access + if let Some([slice_0, ..]) = wrap.inner { + //~^ ERROR: this binding can be a slice pattern to avoid indexing + if wrap.is_super_awesome() { + println!("This is super awesome! {}", slice_0); + } + } + println!("Complete wrap: {:?}", wrap); +} + +/// This would be a nice additional feature to have in the future, but adding it +/// now would make the PR too large. This is therefore only a test that we don't +/// lint cases we can't make a reasonable suggestion for +fn mutable_slice_index() { + // Mut access + let mut slice: Option<[String; 1]> = Some([String::from("Penguin")]); + if let Some(ref mut slice) = slice { + slice[0] = String::from("Mr. Penguin"); + } + println!("Use after modification: {:?}", slice); + + // Mut access on reference + let mut slice: Option<[String; 1]> = Some([String::from("Cat")]); + if let Some(slice) = &mut slice { + slice[0] = String::from("Lord Meow Meow"); + } + println!("Use after modification: {:?}", slice); +} + +/// The lint will ignore bindings with sub patterns as it would be hard +/// to build correct suggestions for these instances :) +fn binding_with_sub_pattern() { + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some(slice @ [_, _, _]) = slice { + println!("{:?}", slice[2]); + } +} + +fn main() {} diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/tests/ui/index_refutable_slice/if_let_slice_binding.rs index a4cb50bd68220..1c1d1c4cbe46b 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -1,8 +1,6 @@ #![deny(clippy::index_refutable_slice)] #![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - enum SomeEnum { One(T), Two(T), diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr index 8819cb0e28bfb..14ee2e54cab10 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:16:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:14:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -9,150 +9,134 @@ note: the lint level is defined here | LL | #![deny(clippy::index_refutable_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([slice_0, ..]) = slice { - | ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([slice_0, ..]) = slice { +LL | +LL ~ println!("{}", slice_0); | -LL | println!("{}", slice_0); - | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:23:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:21:17 | LL | if let Some(slice) = slice { | ^^^^^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([slice_0, ..]) = slice { - | ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([slice_0, ..]) = slice { +LL | +LL ~ println!("{}", slice_0); | -LL | println!("{}", slice_0); - | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:30:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:28:17 | LL | if let Some(slice) = slice { | ^^^^^ | -help: try using a slice pattern here - | -LL | if let Some([slice_0, _, slice_2, ..]) = slice { - | ~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and replace the index expressions here +help: replace the binding and indexed access with a slice pattern | +LL ~ if let Some([slice_0, _, slice_2, ..]) = slice { +LL | LL ~ println!("{}", slice_2); LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:38:26 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:36:26 | LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped { | ^^^^^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped { - | ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped { +LL | +LL ~ println!("{}", slice_0); | -LL | println!("{}", slice_0); - | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:46:29 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:29 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let (SomeEnum::Three([_, _, a_2, ..]), Some(b)) = (a_wrapped, b_wrapped) { - | ~~~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let (SomeEnum::Three([_, _, a_2, ..]), Some(b)) = (a_wrapped, b_wrapped) { +LL | +LL | +LL ~ println!("{} -> {}", a_2, b[1]); | -LL | println!("{} -> {}", a_2, b[1]); - | ~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:46:38 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:38 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let (SomeEnum::Three(a), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) { - | ~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let (SomeEnum::Three(a), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) { +LL | +LL | +LL ~ println!("{} -> {}", a[2], b_1); | -LL | println!("{} -> {}", a[2], b_1); - | ~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:55:21 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:53:21 | LL | if let Some(ref slice) = slice { | ^^^^^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([_, ref slice_1, ..]) = slice { - | ~~~~~~~~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([_, ref slice_1, ..]) = slice { +LL | +LL ~ println!("{:?}", slice_1); | -LL | println!("{:?}", slice_1); - | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:64:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:62:17 | LL | if let Some(slice) = &slice { | ^^^^^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([slice_0, ..]) = &slice { - | ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([slice_0, ..]) = &slice { +LL | +LL ~ println!("{:?}", slice_0); | -LL | println!("{:?}", slice_0); - | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:134:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:132:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([slice_0, ..]) = wrap.inner { - | ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([slice_0, ..]) = wrap.inner { +LL | +LL | if wrap.is_awesome { +LL ~ println!("This is awesome! {}", slice_0); | -LL | println!("This is awesome! {}", slice_0); - | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:142:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:140:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ | -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([slice_0, ..]) = wrap.inner { - | ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([slice_0, ..]) = wrap.inner { +LL | +LL | if wrap.is_super_awesome() { +LL ~ println!("This is super awesome! {}", slice_0); | -LL | println!("This is super awesome! {}", slice_0); - | ~~~~~~~ error: aborting due to 10 previous errors diff --git a/tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed b/tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed new file mode 100644 index 0000000000000..72edc539f0431 --- /dev/null +++ b/tests/ui/index_refutable_slice/slice_indexing_in_macro.fixed @@ -0,0 +1,29 @@ +#![deny(clippy::index_refutable_slice)] + +extern crate if_chain; +use if_chain::if_chain; + +macro_rules! if_let_slice_macro { + () => { + // This would normally be linted + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some(slice) = slice { + println!("{}", slice[0]); + } + }; +} + +fn main() { + // Don't lint this + if_let_slice_macro!(); + + // Do lint this + if_chain! { + let slice: Option<&[u32]> = Some(&[1, 2, 3]); + if let Some([slice_0, ..]) = slice; + //~^ ERROR: this binding can be a slice pattern to avoid indexing + then { + println!("{}", slice_0); + } + } +} diff --git a/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs b/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs index 5d9fad4888999..7b474ba423b9a 100644 --- a/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs +++ b/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs @@ -1,7 +1,5 @@ #![deny(clippy::index_refutable_slice)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - extern crate if_chain; use if_chain::if_chain; diff --git a/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr b/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr index 69f0aaa977785..64741abb91149 100644 --- a/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr +++ b/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/slice_indexing_in_macro.rs:25:21 + --> tests/ui/index_refutable_slice/slice_indexing_in_macro.rs:23:21 | LL | if let Some(slice) = slice; | ^^^^^ @@ -9,14 +9,13 @@ note: the lint level is defined here | LL | #![deny(clippy::index_refutable_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using a slice pattern here +help: replace the binding and indexed access with a slice pattern | -LL | if let Some([slice_0, ..]) = slice; - | ~~~~~~~~~~~~~ -help: and replace the index expressions here +LL ~ if let Some([slice_0, ..]) = slice; +LL | +LL | then { +LL ~ println!("{}", slice_0); | -LL | println!("{}", slice_0); - | ~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/let_unit.fixed b/tests/ui/let_unit.fixed new file mode 100644 index 0000000000000..3456e274f6a4d --- /dev/null +++ b/tests/ui/let_unit.fixed @@ -0,0 +1,196 @@ +#![warn(clippy::let_unit_value)] +#![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)] + +macro_rules! let_and_return { + ($n:expr) => {{ + let ret = $n; + }}; +} + +fn main() { + println!("x"); + let _y = 1; // this is fine + let _z = ((), 1); // this as well + if true { + // do not lint this, since () is explicit + let _a = (); + let () = dummy(); + let () = (); + () = dummy(); + () = (); + let _a: () = (); + let _a: () = dummy(); + } + + consume_units_with_for_loop(); // should be fine as well + + multiline_sugg(); + + let_and_return!(()) // should be fine +} + +fn dummy() {} + +// Related to issue #1964 +fn consume_units_with_for_loop() { + // `for_let_unit` lint should not be triggered by consuming them using for loop. + let v = vec![(), (), ()]; + let mut count = 0; + for _ in v { + count += 1; + } + assert_eq!(count, 3); + + // Same for consuming from some other Iterator. + let (tx, rx) = ::std::sync::mpsc::channel(); + tx.send(()).unwrap(); + drop(tx); + + count = 0; + for _ in rx.iter() { + count += 1; + } + assert_eq!(count, 1); +} + +fn multiline_sugg() { + let v: Vec = vec![2]; + + v + .into_iter() + .map(|i| i * 2) + .filter(|i| i % 2 == 0) + .map(|_| ()) + .next() + .unwrap(); +} + +#[derive(Copy, Clone)] +pub struct ContainsUnit(()); // should be fine + +fn _returns_generic() { + fn f() -> T { + unimplemented!() + } + fn f2(_: T) -> U { + unimplemented!() + } + fn f3(x: T) -> T { + x + } + fn f5(x: bool) -> Option { + x.then(|| T::default()) + } + + let _: () = f(); + let x: () = f(); + + let _: () = f2(0i32); + let x: () = f2(0i32); + + let _: () = f3(()); + let x: () = f3(()); + + fn f4(mut x: Vec) -> T { + x.pop().unwrap() + } + let _: () = f4(vec![()]); + let x: () = f4(vec![()]); + + let _: () = { + let x = 5; + f2(x) + }; + + let _: () = if true { f() } else { f2(0) }; + let x: () = if true { f() } else { f2(0) }; + + match Some(0) { + None => f2(1), + Some(0) => f(), + Some(1) => f2(3), + Some(_) => (), + }; + + let _: () = f5(true).unwrap(); + + #[allow(clippy::let_unit_value)] + { + let x = f(); + let y; + let z; + match 0 { + 0 => { + y = f(); + z = f(); + }, + 1 => { + println!("test"); + y = f(); + z = f3(()); + }, + _ => panic!(), + } + + let x1; + let x2; + if true { + x1 = f(); + x2 = x1; + } else { + x2 = f(); + x1 = x2; + } + + let opt; + match f5(true) { + Some(x) => opt = x, + None => panic!(), + }; + + #[warn(clippy::let_unit_value)] + { + let _: () = x; + let _: () = y; + let _: () = z; + let _: () = x1; + let _: () = x2; + let _: () = opt; + } + } + + let () = f(); +} + +fn attributes() { + fn f() {} + + #[allow(clippy::let_unit_value)] + let _ = f(); + #[expect(clippy::let_unit_value)] + let _ = f(); +} + +async fn issue10433() { + let _pending: () = std::future::pending().await; +} + +pub async fn issue11502(a: ()) {} + +pub fn issue12594() { + fn returns_unit() {} + + fn returns_result(res: T) -> Result { + Ok(res) + } + + fn actual_test() { + // create first a unit value'd value + returns_unit(); + returns_result(()).unwrap(); + returns_result(()).unwrap(); + // make sure we replace only the first variable + let res = 1; + returns_result(res).unwrap(); + } +} diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index 530103ffaf6ec..e2dafbcb77146 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,8 +1,6 @@ #![warn(clippy::let_unit_value)] #![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - macro_rules! let_and_return { ($n:expr) => {{ let ret = $n; diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr index 6f149454af2d0..a2f368f22e5bb 100644 --- a/tests/ui/let_unit.stderr +++ b/tests/ui/let_unit.stderr @@ -1,5 +1,5 @@ error: this let-binding has unit value - --> tests/ui/let_unit.rs:13:5 + --> tests/ui/let_unit.rs:11:5 | LL | let _x = println!("x"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");` @@ -8,7 +8,7 @@ LL | let _x = println!("x"); = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` error: this let-binding has unit value - --> tests/ui/let_unit.rs:61:5 + --> tests/ui/let_unit.rs:59:5 | LL | / let _ = v LL | | .into_iter() @@ -31,7 +31,7 @@ LL + .unwrap(); | error: this let-binding has unit value - --> tests/ui/let_unit.rs:110:5 + --> tests/ui/let_unit.rs:108:5 | LL | / let x = match Some(0) { LL | | None => f2(1), @@ -52,23 +52,17 @@ LL + }; | error: this let-binding has unit value - --> tests/ui/let_unit.rs:191:9 + --> tests/ui/let_unit.rs:189:9 | LL | let res = returns_unit(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: omit the `let` binding - | -LL | returns_unit(); - | -help: variable `res` of type `()` can be replaced with explicit `()` +help: omit the `let` binding and replace variable usages with `()` | -LL | returns_result(()).unwrap(); - | ~~ -help: variable `res` of type `()` can be replaced with explicit `()` +LL ~ returns_unit(); +LL ~ returns_result(()).unwrap(); +LL ~ returns_result(()).unwrap(); | -LL | returns_result(()).unwrap(); - | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/literal_string_with_formatting_arg.rs b/tests/ui/literal_string_with_formatting_arg.rs new file mode 100644 index 0000000000000..f257c66f59d36 --- /dev/null +++ b/tests/ui/literal_string_with_formatting_arg.rs @@ -0,0 +1,37 @@ +#![warn(clippy::literal_string_with_formatting_args)] +#![allow(clippy::unnecessary_literal_unwrap)] + +fn main() { + let x: Option = None; + let y = "hello"; + x.expect("{y} {}"); //~ literal_string_with_formatting_args + x.expect(" {y} bla"); //~ literal_string_with_formatting_args + x.expect("{:?}"); //~ literal_string_with_formatting_args + x.expect("{y:?}"); //~ literal_string_with_formatting_args + x.expect(" {y:?} {y:?} "); //~ literal_string_with_formatting_args + x.expect(" {y:..} {y:?} "); //~ literal_string_with_formatting_args + x.expect(r"{y:?} {y:?} "); //~ literal_string_with_formatting_args + x.expect(r"{y:?} y:?}"); //~ literal_string_with_formatting_args + x.expect(r##" {y:?} {y:?} "##); //~ literal_string_with_formatting_args + // Ensure that it doesn't try to go in the middle of a unicode character. + x.expect("———{:?}"); //~ literal_string_with_formatting_args + + // Should not lint! + format!("{y:?}"); + println!("{y:?}"); + x.expect(" {} "); // We ignore `{}` to limit false positives. + x.expect(" { } "); // We ignore `{}` to limit false positives. + x.expect("{{y} {x"); + x.expect("{{y:?}"); + x.expect(" {0}"); // If it only contains an integer, we ignore it. + x.expect(r##" {x:?} "##); // `x` doesn't exist so we shoud not lint + x.expect("{y:...}"); + let _ = "fn main {\n\ + }"; + // Unicode characters escape should not lint either. + "\u{0052}".to_string(); + + // Regression test for . + let x: Option = Some(0); + x.expect("{…}"); +} diff --git a/tests/ui/literal_string_with_formatting_arg.stderr b/tests/ui/literal_string_with_formatting_arg.stderr new file mode 100644 index 0000000000000..32a84f600da72 --- /dev/null +++ b/tests/ui/literal_string_with_formatting_arg.stderr @@ -0,0 +1,71 @@ +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:7:15 + | +LL | x.expect("{y} {}"); + | ^^^ + | + = note: `-D clippy::literal-string-with-formatting-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::literal_string_with_formatting_args)]` + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:8:16 + | +LL | x.expect(" {y} bla"); + | ^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:9:15 + | +LL | x.expect("{:?}"); + | ^^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:10:15 + | +LL | x.expect("{y:?}"); + | ^^^^^ + +error: these look like formatting arguments but are not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:11:16 + | +LL | x.expect(" {y:?} {y:?} "); + | ^^^^^ ^^^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:12:23 + | +LL | x.expect(" {y:..} {y:?} "); + | ^^^^^ + +error: these look like formatting arguments but are not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:13:16 + | +LL | x.expect(r"{y:?} {y:?} "); + | ^^^^^ ^^^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:14:16 + | +LL | x.expect(r"{y:?} y:?}"); + | ^^^^^ + +error: these look like formatting arguments but are not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:15:19 + | +LL | x.expect(r##" {y:?} {y:?} "##); + | ^^^^^ ^^^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:17:18 + | +LL | x.expect("———{:?}"); + | ^^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:27:19 + | +LL | x.expect(r##" {x:?} "##); // `x` doesn't exist so we shoud not lint + | ^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed new file mode 100644 index 0000000000000..dc1cb8e11fca6 --- /dev/null +++ b/tests/ui/manual_async_fn.fixed @@ -0,0 +1,116 @@ +#![warn(clippy::manual_async_fn)] +#![allow(clippy::needless_pub_self, unused)] + +use std::future::Future; + +async fn fut() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut2() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut3() -> i32 { 42 } + +async fn empty_fut() {} + +#[rustfmt::skip] +async fn empty_fut2() {} + +#[rustfmt::skip] +async fn empty_fut3() {} + +async fn core_fut() -> i32 { 42 } + +// should be ignored +fn has_other_stmts() -> impl core::future::Future { + let _ = 42; + async move { 42 } +} + +// should be ignored +fn not_fut() -> i32 { + 42 +} + +// should be ignored +async fn already_async() -> impl Future { + async { 42 } +} + +struct S; +impl S { + async fn inh_fut() -> i32 { + // NOTE: this code is here just to check that the indentation is correct in the suggested fix + let a = 42; + let b = 21; + if a < b { + let c = 21; + let d = 42; + if c < d { + let _ = 42; + } + } + 42 + } + + // should be ignored + fn not_fut(&self) -> i32 { + 42 + } + + // should be ignored + fn has_other_stmts() -> impl core::future::Future { + let _ = 42; + async move { 42 } + } + + // should be ignored + async fn already_async(&self) -> impl Future { + async { 42 } + } +} + +// Tests related to lifetime capture + +async fn elided(_: &i32) -> i32 { 42 } + +// should be ignored +fn elided_not_bound(_: &i32) -> impl Future { + async { 42 } +} + +#[allow(clippy::needless_lifetimes)] +async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } + +// should be ignored +#[allow(clippy::needless_lifetimes)] +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future { + async { 42 } +} + +// should be ignored +mod issue_5765 { + use std::future::Future; + + struct A; + impl A { + fn f(&self) -> impl Future { + async {} + } + } + + fn test() { + let _future = { + let a = A; + a.f() + }; + } +} + +pub async fn issue_10450() -> i32 { 42 } + +pub(crate) async fn issue_10450_2() -> i32 { 42 } + +pub(self) async fn issue_10450_3() -> i32 { 42 } + +fn main() {} diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index 6b8ac5033a92d..9ca7654a36882 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,8 +1,6 @@ #![warn(clippy::manual_async_fn)] #![allow(clippy::needless_pub_self, unused)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::future::Future; fn fut() -> impl Future { @@ -99,6 +97,7 @@ fn elided_not_bound(_: &i32) -> impl Future { async { 42 } } +#[allow(clippy::needless_lifetimes)] fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { async { 42 } } diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index f88fc30b3b54e..68a97243436df 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -1,5 +1,5 @@ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:8:1 + --> tests/ui/manual_async_fn.rs:6:1 | LL | fn fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,116 +8,84 @@ LL | fn fut() -> impl Future { = help: to override `-D warnings` add `#[allow(clippy::manual_async_fn)]` help: make the function `async` and return the output of the future directly | -LL | async fn fut() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn fut() -> impl Future { 42 } - | ~~~~~~ +LL | async fn fut() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:13:1 + --> tests/ui/manual_async_fn.rs:11:1 | LL | fn fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn fut2() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn fut2() ->impl Future { 42 } - | ~~~~~~ +LL | async fn fut2() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:18:1 + --> tests/ui/manual_async_fn.rs:16:1 | LL | fn fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn fut3() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn fut3()-> impl Future { 42 } - | ~~~~~~ +LL | async fn fut3() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:22:1 + --> tests/ui/manual_async_fn.rs:20:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: make the function `async` and remove the return type - | -LL | async fn empty_fut() { - | ~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function +help: make the function `async` and return the output of the future directly | -LL | fn empty_fut() -> impl Future {} - | ~~ +LL | async fn empty_fut() {} + | ~~~~~~~~~~~~~~~~~~~~ ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:27:1 + --> tests/ui/manual_async_fn.rs:25:1 | LL | fn empty_fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: make the function `async` and remove the return type - | -LL | async fn empty_fut2() { - | ~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function +help: make the function `async` and return the output of the future directly | -LL | fn empty_fut2() ->impl Future {} - | ~~ +LL | async fn empty_fut2() {} + | ~~~~~~~~~~~~~~~~~~~~~ ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:32:1 + --> tests/ui/manual_async_fn.rs:30:1 | LL | fn empty_fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: make the function `async` and remove the return type - | -LL | async fn empty_fut3() { - | ~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function +help: make the function `async` and return the output of the future directly | -LL | fn empty_fut3()-> impl Future {} - | ~~ +LL | async fn empty_fut3() {} + | ~~~~~~~~~~~~~~~~~~~~~ ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:36:1 + --> tests/ui/manual_async_fn.rs:34:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn core_fut() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn core_fut() -> impl core::future::Future { 42 } - | ~~~~~~ +LL | async fn core_fut() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:58:5 + --> tests/ui/manual_async_fn.rs:56:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn inh_fut() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL ~ fn inh_fut() -> impl Future { +LL ~ async fn inh_fut() -> i32 { LL + // NOTE: this code is here just to check that the indentation is correct in the suggested fix LL + let a = 42; LL + let b = 21; @@ -133,79 +101,59 @@ LL + } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:93:1 + --> tests/ui/manual_async_fn.rs:91:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn elided(_: &i32) -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn elided(_: &i32) -> impl Future + '_ { 42 } - | ~~~~~~ +LL | async fn elided(_: &i32) -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:102:1 + --> tests/ui/manual_async_fn.rs:101:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } - | ~~~~~~ +LL | async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:131:1 + --> tests/ui/manual_async_fn.rs:130:1 | LL | pub fn issue_10450() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | pub async fn issue_10450() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | pub fn issue_10450() -> impl Future { 42 } - | ~~~~~~ +LL | pub async fn issue_10450() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:135:1 + --> tests/ui/manual_async_fn.rs:134:1 | LL | pub(crate) fn issue_10450_2() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | pub(crate) async fn issue_10450_2() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | pub(crate) fn issue_10450_2() -> impl Future { 42 } - | ~~~~~~ +LL | pub(crate) async fn issue_10450_2() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:139:1 + --> tests/ui/manual_async_fn.rs:138:1 | LL | pub(self) fn issue_10450_3() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | pub(self) async fn issue_10450_3() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | pub(self) fn issue_10450_3() -> impl Future { 42 } - | ~~~~~~ +LL | pub(self) async fn issue_10450_3() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: aborting due to 13 previous errors diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed new file mode 100644 index 0000000000000..aaac6a048e1d0 --- /dev/null +++ b/tests/ui/manual_split_once.fixed @@ -0,0 +1,144 @@ +#![warn(clippy::manual_split_once)] +#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let _ = "key=value".splitn(2, '=').nth(2); + let _ = "key=value".split_once('=').unwrap().1; + let _ = "key=value".split_once('=').unwrap().1; + let (_, _) = "key=value".split_once('=').unwrap(); + + let s = String::from("key=value"); + let _ = s.split_once('=').unwrap().1; + + let s = Box::::from("key=value"); + let _ = s.split_once('=').unwrap().1; + + let s = &"key=value"; + let _ = s.split_once('=').unwrap().1; + + fn _f(s: &str) -> Option<&str> { + let _ = s.split_once('=')?.1; + let _ = s.split_once('=')?.1; + let _ = s.rsplit_once('=')?.0; + let _ = s.rsplit_once('=')?.0; + None + } + + // Don't lint, slices don't have `split_once` + let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); + + // `rsplitn` gives the results in the reverse order of `rsplit_once` + let _ = "key=value".rsplit_once('=').unwrap().0; + let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); + let _ = s.rsplit_once('=').map(|x| x.0); +} + +fn indirect() -> Option<()> { + let (l, r) = "a.b.c".split_once('.').unwrap(); + + + + let (l, r) = "a.b.c".split_once('.')?; + + + + let (l, r) = "a.b.c".rsplit_once('.').unwrap(); + + + + let (l, r) = "a.b.c".rsplit_once('.')?; + + + + // could lint, currently doesn't + + let mut iter = "a.b.c".splitn(2, '.'); + let other = 1; + let l = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let mut mut_binding = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let tuple = (iter.next()?, iter.next()?); + + // should not lint + + let mut missing_unwrap = "a.b.c".splitn(2, '.'); + let l = missing_unwrap.next(); + let r = missing_unwrap.next(); + + let mut mixed_unrap = "a.b.c".splitn(2, '.'); + let unwrap = mixed_unrap.next().unwrap(); + let question_mark = mixed_unrap.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let same_name = iter.next()?; + let same_name = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let shadows_existing = "d"; + let shadows_existing = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let becomes_shadowed = iter.next()?; + let becomes_shadowed = "d"; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + let r = iter.next()?; + let third_usage = iter.next()?; + + let mut n_three = "a.b.c".splitn(3, '.'); + let l = n_three.next()?; + let r = n_three.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + { + let in_block = iter.next()?; + } + let r = iter.next()?; + + let mut lacks_binding = "a.b.c".splitn(2, '.'); + let _ = lacks_binding.next()?; + let r = lacks_binding.next()?; + + let mut mapped = "a.b.c".splitn(2, '.').map(|_| "~"); + let l = iter.next()?; + let r = iter.next()?; + + let mut assigned = ""; + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + assigned = iter.next()?; + + None +} + +#[clippy::msrv = "1.51"] +fn _msrv_1_51() { + // `str::split_once` was stabilized in 1.52. Do not lint this + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + + let mut iter = "a.b.c".splitn(2, '.'); + let a = iter.next().unwrap(); + let b = iter.next().unwrap(); +} + +#[clippy::msrv = "1.52"] +fn _msrv_1_52() { + let _ = "key=value".split_once('=').unwrap().1; + + let (a, b) = "a.b.c".split_once('.').unwrap(); + + +} diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index e13c827468b83..113e1737c97da 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -1,8 +1,6 @@ #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - extern crate itertools; #[allow(unused_imports)] diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index 566204ad8762e..366d860f25efd 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -1,5 +1,5 @@ error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:13:13 + --> tests/ui/manual_split_once.rs:11:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` @@ -8,79 +8,79 @@ LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::manual_split_once)]` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:14:13 + --> tests/ui/manual_split_once.rs:12:13 | LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:15:18 + --> tests/ui/manual_split_once.rs:13:18 | LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=')` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:18:13 + --> tests/ui/manual_split_once.rs:16:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:21:13 + --> tests/ui/manual_split_once.rs:19:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:24:13 + --> tests/ui/manual_split_once.rs:22:13 | LL | let _ = s.splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:27:17 + --> tests/ui/manual_split_once.rs:25:17 | LL | let _ = s.splitn(2, '=').nth(1)?; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:28:17 + --> tests/ui/manual_split_once.rs:26:17 | LL | let _ = s.splitn(2, '=').skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:29:17 + --> tests/ui/manual_split_once.rs:27:17 | LL | let _ = s.rsplitn(2, '=').nth(1)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:30:17 + --> tests/ui/manual_split_once.rs:28:17 | LL | let _ = s.rsplitn(2, '=').skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:38:13 + --> tests/ui/manual_split_once.rs:36:13 | LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').unwrap().0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:39:18 + --> tests/ui/manual_split_once.rs:37:18 | LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:40:13 + --> tests/ui/manual_split_once.rs:38:13 | LL | let _ = s.rsplitn(2, '=').nth(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=').map(|x| x.0)` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:44:5 + --> tests/ui/manual_split_once.rs:42:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,21 +89,15 @@ LL | let l = iter.next().unwrap(); LL | let r = iter.next().unwrap(); | ----------------------------- second usage here | -help: try `split_once` - | -LL | let (l, r) = "a.b.c".split_once('.').unwrap(); +help: replace with `split_once` | -help: remove the `iter` usages - | -LL - let l = iter.next().unwrap(); - | -help: remove the `iter` usages - | -LL - let r = iter.next().unwrap(); +LL ~ let (l, r) = "a.b.c".split_once('.').unwrap(); +LL ~ +LL ~ | error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:48:5 + --> tests/ui/manual_split_once.rs:46:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,21 +106,15 @@ LL | let l = iter.next()?; LL | let r = iter.next()?; | --------------------- second usage here | -help: try `split_once` - | -LL | let (l, r) = "a.b.c".split_once('.')?; - | -help: remove the `iter` usages - | -LL - let l = iter.next()?; +help: replace with `split_once` | -help: remove the `iter` usages - | -LL - let r = iter.next()?; +LL ~ let (l, r) = "a.b.c".split_once('.')?; +LL ~ +LL ~ | error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:52:5 + --> tests/ui/manual_split_once.rs:50:5 | LL | let mut iter = "a.b.c".rsplitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,21 +123,15 @@ LL | let r = iter.next().unwrap(); LL | let l = iter.next().unwrap(); | ----------------------------- second usage here | -help: try `rsplit_once` - | -LL | let (l, r) = "a.b.c".rsplit_once('.').unwrap(); - | -help: remove the `iter` usages - | -LL - let r = iter.next().unwrap(); +help: replace with `rsplit_once` | -help: remove the `iter` usages - | -LL - let l = iter.next().unwrap(); +LL ~ let (l, r) = "a.b.c".rsplit_once('.').unwrap(); +LL ~ +LL ~ | error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:56:5 + --> tests/ui/manual_split_once.rs:54:5 | LL | let mut iter = "a.b.c".rsplitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,27 +140,21 @@ LL | let r = iter.next()?; LL | let l = iter.next()?; | --------------------- second usage here | -help: try `rsplit_once` - | -LL | let (l, r) = "a.b.c".rsplit_once('.')?; - | -help: remove the `iter` usages +help: replace with `rsplit_once` | -LL - let r = iter.next()?; - | -help: remove the `iter` usages - | -LL - let l = iter.next()?; +LL ~ let (l, r) = "a.b.c".rsplit_once('.')?; +LL ~ +LL ~ | error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:141:13 + --> tests/ui/manual_split_once.rs:139:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:143:5 + --> tests/ui/manual_split_once.rs:141:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -187,17 +163,11 @@ LL | let a = iter.next().unwrap(); LL | let b = iter.next().unwrap(); | ----------------------------- second usage here | -help: try `split_once` - | -LL | let (a, b) = "a.b.c".split_once('.').unwrap(); - | -help: remove the `iter` usages - | -LL - let a = iter.next().unwrap(); - | -help: remove the `iter` usages +help: replace with `split_once` | -LL - let b = iter.next().unwrap(); +LL ~ let (a, b) = "a.b.c".split_once('.').unwrap(); +LL ~ +LL ~ | error: aborting due to 19 previous errors diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr index 3c0382767c3fc..4a4772da143a2 100644 --- a/tests/ui/match_same_arms.stderr +++ b/tests/ui/match_same_arms.stderr @@ -20,13 +20,10 @@ LL | (1, .., 3) => 42, | ^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns +help: or try merging the arm patterns and removing the obsolete arm | -LL | (1, .., 3) | (.., 3) => 42, - | ~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm - | -LL - (.., 3) => 42, +LL ~ (1, .., 3) | (.., 3) => 42, +LL ~ _ => 0, | error: this match arm has an identical body to another arm @@ -36,13 +33,11 @@ LL | 51 => 1, | ^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | 51 | 42 => 1, - | ~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - 42 => 1, +LL - 51 => 1, +LL + 51 | 42 => 1, | error: this match arm has an identical body to another arm @@ -52,13 +47,10 @@ LL | 41 => 2, | ^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns +help: or try merging the arm patterns and removing the obsolete arm | -LL | 41 | 52 => 2, - | ~~~~~~~ -help: and remove this obsolete arm - | -LL - 52 => 2, +LL ~ 41 | 52 => 2, +LL ~ _ => 0, | error: this match arm has an identical body to another arm @@ -68,13 +60,11 @@ LL | 2 => 2, | ^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | 2 | 1 => 2, - | ~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - 1 => 2, +LL - 2 => 2, +LL + 2 | 1 => 2, | error: this match arm has an identical body to another arm @@ -84,13 +74,11 @@ LL | 3 => 2, | ^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns +help: or try merging the arm patterns and removing the obsolete arm | -LL | 3 | 1 => 2, - | ~~~~~ -help: and remove this obsolete arm - | -LL - 1 => 2, +LL ~ 2 => 2, +LL | +LL ~ 3 | 1 => 2, | error: this match arm has an identical body to another arm @@ -100,14 +88,11 @@ LL | 2 => 2, | ^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns +help: or try merging the arm patterns and removing the obsolete arm | -LL | 2 | 3 => 2, - | ~~~~~ -help: and remove this obsolete arm - | -LL - 3 => 2, -LL + +LL ~ 2 | 3 => 2, +LL | +LL ~ | error: this match arm has an identical body to another arm @@ -117,13 +102,11 @@ LL | CommandInfo::External { name, .. } => name.to_string(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(), - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - CommandInfo::BuiltIn { name, .. } => name.to_string(), +LL - CommandInfo::External { name, .. } => name.to_string(), +LL + CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(), | error: aborting due to 8 previous errors diff --git a/tests/ui/match_same_arms2.fixed b/tests/ui/match_same_arms2.fixed new file mode 100644 index 0000000000000..b7d377f1ebffc --- /dev/null +++ b/tests/ui/match_same_arms2.fixed @@ -0,0 +1,259 @@ +#![warn(clippy::match_same_arms)] +#![allow( + clippy::disallowed_names, + clippy::diverging_sub_expression, + clippy::uninlined_format_args, + clippy::match_single_binding, + clippy::match_like_matches_macro +)] + +fn bar(_: T) {} +fn foo() -> bool { + unimplemented!() +} + +fn match_same_arms() { + let _ = match 42 { + _ => { + foo(); + let mut a = 42 + [23].len() as i32; + if true { + a += 7; + } + a = -31 - a; + a + }, + }; + //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm + + let _ = match 42 { + 51 | 42 => foo(), //~ ERROR: this match arm has an identical body to another arm + _ => true, + }; + + let _ = match Some(42) { + None | Some(_) => 24, //~ ERROR: this match arm has an identical body to another arm + }; + + let _ = match Some(42) { + Some(foo) => 24, + None => 24, + }; + + let _ = match Some(42) { + Some(42) => 24, + Some(a) => 24, // bindings are different + None => 0, + }; + + let _ = match Some(42) { + Some(a) if a > 0 => 24, + Some(a) => 24, // one arm has a guard + None => 0, + }; + + match (Some(42), Some(42)) { + (None, Some(a)) | (Some(a), None) => bar(a), //~ ERROR: this match arm has an identical body to another arm + _ => (), + } + + // No warning because guards are different + let _ = match Some(42) { + Some(a) if a == 42 => a, + Some(a) if a == 24 => a, + Some(_) => 24, + None => 0, + }; + + let _ = match (Some(42), Some(42)) { + (None, Some(a)) | (Some(a), None) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm + _ => 0, + }; + + match (Some(42), Some(42)) { + (Some(a), ..) | (.., Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm + _ => (), + } + + let _ = match Some(()) { + Some(()) => 0.0, + None => -0.0, + }; + + match (Some(42), Some("")) { + (Some(a), None) => bar(a), + (None, Some(a)) => bar(a), // bindings have different types + _ => (), + } + + let x: Result = Ok(3); + + // No warning because of the guard. + match x { + Ok(x) if x * x == 64 => println!("ok"), + Ok(_) => println!("ok"), + Err(_) => println!("err"), + } + + // This used to be a false positive; see issue #1996. + match x { + Ok(3) => println!("ok"), + Ok(x) if x * x == 64 => println!("ok 64"), + Ok(_) => println!("ok"), + Err(_) => println!("err"), + } + + match (x, Some(1i32)) { + (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm + _ => println!("err"), + } + + // No warning; different types for `x`. + match (x, Some(1.0f64)) { + (Ok(x), Some(_)) => println!("ok {}", x), + (Ok(_), Some(x)) => println!("ok {}", x), + _ => println!("err"), + } + + // False negative #2251. + match x { + Ok(_tmp) => println!("ok"), + Ok(_) | Ok(3) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm + Err(_) => { + unreachable!(); + }, + } + + // False positive #1390 + macro_rules! empty { + ($e:expr) => {}; + } + match 0 { + 0 => { + empty!(0); + }, + 1 => { + empty!(1); + }, + x => { + empty!(x); + }, + }; + + // still lint if the tokens are the same + match 0 { + 1 | 0 => { + empty!(0); + }, + x => { + empty!(x); + }, + } + //~^^^^^^^ ERROR: this match arm has an identical body to another arm + + match_expr_like_matches_macro_priority(); +} + +fn match_expr_like_matches_macro_priority() { + enum E { + A, + B, + C, + } + let x = E::A; + let _ans = match x { + E::A => false, + E::B => false, + _ => true, + }; +} + +fn main() { + let _ = match Some(0) { + Some(0) => 0, + Some(1) => 1, + #[cfg(feature = "foo")] + Some(2) => 2, + _ => 1, + }; + + enum Foo { + X(u32), + Y(u32), + Z(u32), + } + + // Don't lint. `Foo::X(0)` and `Foo::Z(_)` overlap with the arm in between. + let _ = match Foo::X(0) { + Foo::X(0) => 1, + Foo::X(_) | Foo::Y(_) | Foo::Z(0) => 2, + Foo::Z(_) => 1, + _ => 0, + }; + + // Suggest moving `Foo::Z(_)` up. + let _ = match Foo::X(0) { + Foo::X(0) | Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm + Foo::X(_) | Foo::Y(_) => 2, + _ => 0, + }; + + // Suggest moving `Foo::X(0)` down. + let _ = match Foo::X(0) { + Foo::Y(_) | Foo::Z(0) => 2, + Foo::Z(_) | Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm + _ => 0, + }; + + // Don't lint. + let _ = match 0 { + -2 => 1, + -5..=50 => 2, + -150..=88 => 1, + _ => 3, + }; + + struct Bar { + x: u32, + y: u32, + z: u32, + } + + // Lint. + let _ = match None { + Some(Bar { y: 10, z: 0, .. }) => 2, + None => 50, + Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm + _ => 200, + }; + + let _ = match 0 { + 0 => todo!(), + 1 => todo!(), + 2 => core::convert::identity::(todo!()), + 3 => core::convert::identity::(todo!()), + _ => 5, + }; + + let _ = match 0 { + 1 | 0 => cfg!(not_enable), + _ => 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 dedd02e78733f..dfd15d10c3d34 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -7,8 +7,6 @@ clippy::match_like_matches_macro )] -//@no-rustfix: need to change the suggestion to a multipart suggestion - fn bar(_: T) {} fn foo() -> bool { unimplemented!() diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 3a28b5afc2b8a..525a25e9287be 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -1,5 +1,5 @@ error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms2.rs:19:9 + --> tests/ui/match_same_arms2.rs:17:9 | LL | / 42 => { LL | | foo(); @@ -12,7 +12,7 @@ LL | | _ => { | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms2.rs:28:9 + --> tests/ui/match_same_arms2.rs:26:9 | LL | / _ => { LL | | foo(); @@ -26,119 +26,103 @@ LL | | }, = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:42:9 + --> tests/ui/match_same_arms2.rs:40:9 | LL | 51 => foo(), | ^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | 51 | 42 => foo(), - | ~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - 42 => foo(), +LL - 51 => foo(), +LL + 51 | 42 => foo(), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:48:9 + --> tests/ui/match_same_arms2.rs:46:9 | LL | None => 24, | ^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | None | Some(_) => 24, - | ~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - Some(_) => 24, +LL - None => 24, +LL + None | Some(_) => 24, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:70:9 + --> tests/ui/match_same_arms2.rs:68:9 | LL | (None, Some(a)) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | (None, Some(a)) | (Some(a), None) => bar(a), - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - (Some(a), None) => bar(a), +LL - (None, Some(a)) => bar(a), +LL + (None, Some(a)) | (Some(a), None) => bar(a), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:84:9 + --> tests/ui/match_same_arms2.rs:82:9 | LL | (None, Some(a)) if a == 42 => a, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | (None, Some(a)) | (Some(a), None) if a == 42 => a, - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - (Some(a), None) if a == 42 => a, +LL - (None, Some(a)) if a == 42 => a, +LL + (None, Some(a)) | (Some(a), None) if a == 42 => a, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:89:9 + --> tests/ui/match_same_arms2.rs:87:9 | LL | (Some(a), ..) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns +help: or try merging the arm patterns and removing the obsolete arm | -LL | (Some(a), ..) | (.., Some(a)) => bar(a), - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm - | -LL - (.., Some(a)) => bar(a), +LL ~ (Some(a), ..) | (.., Some(a)) => bar(a), +LL ~ _ => (), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:123:9 + --> tests/ui/match_same_arms2.rs:121:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | -LL - (Ok(_), Some(x)) => println!("ok {}", x), +LL ~ (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), +LL ~ _ => println!("err"), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:139:9 + --> tests/ui/match_same_arms2.rs:137:9 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | Ok(_) | Ok(3) => println!("ok"), - | ~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - Ok(3) => println!("ok"), +LL - Ok(_) => println!("ok"), +LL + Ok(_) | Ok(3) => println!("ok"), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:166:9 + --> tests/ui/match_same_arms2.rs:164:9 | LL | / 1 => { LL | | empty!(0); @@ -146,95 +130,82 @@ LL | | }, | |_________^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | 1 | 0 => { - | ~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - 0 => { LL - empty!(0); LL - }, +LL - 1 => { +LL + 1 | 0 => { | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:217:9 + --> tests/ui/match_same_arms2.rs:215:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | Foo::X(0) | Foo::Z(_) => 1, - | ~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | -LL - Foo::Z(_) => 1, +LL ~ Foo::X(0) | Foo::Z(_) => 1, +LL | Foo::X(_) | Foo::Y(_) => 2, +LL ~ _ => 0, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:227:9 + --> tests/ui/match_same_arms2.rs:225:9 | LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | Foo::Z(_) | Foo::X(0) => 1, - | ~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | -LL - Foo::X(0) => 1, +LL ~ Foo::Y(_) | Foo::Z(0) => 2, +LL ~ Foo::Z(_) | Foo::X(0) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:250:9 + --> tests/ui/match_same_arms2.rs:248:9 | LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns +help: or try merging the arm patterns and removing the obsolete arm | -LL | Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: and remove this obsolete arm - | -LL - Some(Bar { x: 0, y: 5, .. }) => 1, +LL ~ Some(Bar { y: 10, z: 0, .. }) => 2, +LL | None => 50, +LL ~ Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:264:9 + --> tests/ui/match_same_arms2.rs:262:9 | LL | 1 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ | = help: try changing either arm body -help: or try merging the arm patterns - | -LL | 1 | 0 => cfg!(not_enable), - | ~~~~~ -help: and remove this obsolete arm +help: or try merging the arm patterns and removing the obsolete arm | LL - 0 => cfg!(not_enable), +LL - 1 => cfg!(not_enable), +LL + 1 | 0 => cfg!(not_enable), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:280:17 + --> tests/ui/match_same_arms2.rs:278: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 +help: or try merging the arm patterns and removing the obsolete arm | LL - MaybeStaticStr::Static(s) => s, +LL - MaybeStaticStr::Borrowed(s) => s, +LL + MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, | error: aborting due to 14 previous errors diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index f255cb666528f..b92d9379c904b 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -23,3 +23,9 @@ fn main() { fn foo() {} ); } + +#[cfg_attr(all(), deprecated)] +fn issue_12320() {} + +#[cfg_attr(all(), deprecated, doc = "foo")] +fn issue_12320_2() {} diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index 1305910ed0e5c..c77e728275048 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -26,3 +26,9 @@ fn main() { fn foo() {} ); } + +#[cfg_attr(all(), must_use, deprecated)] +fn issue_12320() {} + +#[cfg_attr(all(), deprecated, doc = "foo", must_use)] +fn issue_12320_2() {} diff --git a/tests/ui/must_use_unit.stderr b/tests/ui/must_use_unit.stderr index c2ee2edda7dc5..b435568deeab8 100644 --- a/tests/ui/must_use_unit.stderr +++ b/tests/ui/must_use_unit.stderr @@ -25,5 +25,21 @@ LL | #[must_use = "With note"] LL | pub fn must_use_with_note() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: this unit-returning function has a `#[must_use]` attribute + --> tests/ui/must_use_unit.rs:31:1 + | +LL | #[cfg_attr(all(), must_use, deprecated)] + | -------------------- help: change these attributes to: `deprecated` +LL | fn issue_12320() {} + | ^^^^^^^^^^^^^^^^ + +error: this unit-returning function has a `#[must_use]` attribute + --> tests/ui/must_use_unit.rs:34:1 + | +LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)] + | --------------------------------- help: change these attributes to: `deprecated, doc = "foo"` +LL | fn issue_12320_2() {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index cfa4cf9da3c56..8196d608abd21 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -562,4 +562,18 @@ mod rayon { } } +mod issue13749 { + pub struct Generic(T); + // Non elidable lifetime + #[expect(clippy::extra_unused_lifetimes)] + impl<'a, T> Generic where T: 'a {} +} + +mod issue13749bis { + pub struct Generic(T); + // Non elidable lifetime + #[expect(clippy::extra_unused_lifetimes)] + impl<'a, T: 'a> Generic {} +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 5e9d51164268b..b55dd99c46d05 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -562,4 +562,18 @@ mod rayon { } } +mod issue13749 { + pub struct Generic(T); + // Non elidable lifetime + #[expect(clippy::extra_unused_lifetimes)] + impl<'a, T> Generic where T: 'a {} +} + +mod issue13749bis { + pub struct Generic(T); + // Non elidable lifetime + #[expect(clippy::extra_unused_lifetimes)] + impl<'a, T: 'a> Generic {} +} + fn main() {} diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed index a936eb463f964..06c6169d0da0b 100644 --- a/tests/ui/needless_match.fixed +++ b/tests/ui/needless_match.fixed @@ -245,4 +245,57 @@ mod issue9084 { } } +fn a() -> Option<()> { + Some(()) +} +fn b() -> Option<()> { + Some(()) +} +fn c() -> Option<()> { + Some(()) +} + +#[allow(clippy::ifs_same_cond)] +pub fn issue13574() -> Option<()> { + // Do not lint. + // The right hand of all these arms are different functions. + let _ = { + if let Some(a) = a() { + Some(a) + } else if let Some(b) = b() { + Some(b) + } else if let Some(c) = c() { + Some(c) + } else { + None + } + }; + + const A: Option<()> = Some(()); + const B: Option<()> = Some(()); + const C: Option<()> = Some(()); + const D: Option<()> = Some(()); + + let _ = { + if let Some(num) = A { + Some(num) + } else if let Some(num) = B { + Some(num) + } else if let Some(num) = C { + Some(num) + } else if let Some(num) = D { + Some(num) + } else { + None + } + }; + + // Same const, should lint + let _ = { + A + }; + + None +} + fn main() {} diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs index b1dd6ff075d88..6b71de68e1be7 100644 --- a/tests/ui/needless_match.rs +++ b/tests/ui/needless_match.rs @@ -289,4 +289,65 @@ mod issue9084 { } } +fn a() -> Option<()> { + Some(()) +} +fn b() -> Option<()> { + Some(()) +} +fn c() -> Option<()> { + Some(()) +} + +#[allow(clippy::ifs_same_cond)] +pub fn issue13574() -> Option<()> { + // Do not lint. + // The right hand of all these arms are different functions. + let _ = { + if let Some(a) = a() { + Some(a) + } else if let Some(b) = b() { + Some(b) + } else if let Some(c) = c() { + Some(c) + } else { + None + } + }; + + const A: Option<()> = Some(()); + const B: Option<()> = Some(()); + const C: Option<()> = Some(()); + const D: Option<()> = Some(()); + + let _ = { + if let Some(num) = A { + Some(num) + } else if let Some(num) = B { + Some(num) + } else if let Some(num) = C { + Some(num) + } else if let Some(num) = D { + Some(num) + } else { + None + } + }; + + // Same const, should lint + let _ = { + if let Some(num) = A { + Some(num) + } else if let Some(num) = A { + Some(num) + } else if let Some(num) = A { + Some(num) + } else { + None + } + }; + + None +} + fn main() {} diff --git a/tests/ui/needless_match.stderr b/tests/ui/needless_match.stderr index 5bcab467aeae3..1410585cb2e3e 100644 --- a/tests/ui/needless_match.stderr +++ b/tests/ui/needless_match.stderr @@ -131,5 +131,17 @@ LL | | _ => e, LL | | }; | |_________^ help: replace it with: `e` -error: aborting due to 13 previous errors +error: this if-let expression is unnecessary + --> tests/ui/needless_match.rs:339:9 + | +LL | / if let Some(num) = A { +LL | | Some(num) +LL | | } else if let Some(num) = A { +LL | | Some(num) +... | +LL | | None +LL | | } + | |_________^ help: replace it with: `A` + +error: aborting due to 14 previous errors diff --git a/tests/ui/needless_option_take.fixed b/tests/ui/needless_option_take.fixed deleted file mode 100644 index d732a2686cb9d..0000000000000 --- a/tests/ui/needless_option_take.fixed +++ /dev/null @@ -1,13 +0,0 @@ -fn main() { - println!("Testing non erroneous option_take_on_temporary"); - let mut option = Some(1); - let _ = Box::new(move || option.take().unwrap()); - - println!("Testing non erroneous option_take_on_temporary"); - let x = Some(3); - x.as_ref(); - - println!("Testing erroneous option_take_on_temporary"); - let x = Some(3); - x.as_ref(); -} diff --git a/tests/ui/needless_option_take.rs b/tests/ui/needless_option_take.rs index f947d874e064b..c6807718a758e 100644 --- a/tests/ui/needless_option_take.rs +++ b/tests/ui/needless_option_take.rs @@ -1,3 +1,15 @@ +struct MyStruct; + +impl MyStruct { + pub fn get_option() -> Option { + todo!() + } +} + +fn return_option() -> Option { + todo!() +} + fn main() { println!("Testing non erroneous option_take_on_temporary"); let mut option = Some(1); @@ -7,7 +19,40 @@ fn main() { let x = Some(3); x.as_ref(); - println!("Testing erroneous option_take_on_temporary"); let x = Some(3); x.as_ref().take(); + //~^ ERROR: called `Option::take()` on a temporary value + + println!("Testing non erroneous option_take_on_temporary"); + let mut x = Some(3); + let y = x.as_mut(); + + let mut x = Some(3); + let y = x.as_mut().take(); + //~^ ERROR: called `Option::take()` on a temporary value + let y = x.replace(289).take(); + //~^ ERROR: called `Option::take()` on a temporary value + + let y = Some(3).as_mut().take(); + //~^ ERROR: called `Option::take()` on a temporary value + + let y = Option::as_mut(&mut x).take(); + //~^ ERROR: called `Option::take()` on a temporary value + + let x = return_option(); + let x = return_option().take(); + //~^ ERROR: called `Option::take()` on a temporary value + + let x = MyStruct::get_option(); + let x = MyStruct::get_option().take(); + //~^ ERROR: called `Option::take()` on a temporary value + + let mut my_vec = vec![1, 2, 3]; + my_vec.push(4); + let y = my_vec.first(); + let y = my_vec.first().take(); + //~^ ERROR: called `Option::take()` on a temporary value + + let y = my_vec.first().take(); + //~^ ERROR: called `Option::take()` on a temporary value } diff --git a/tests/ui/needless_option_take.stderr b/tests/ui/needless_option_take.stderr index 4a73ccb86d081..e036bd53170ab 100644 --- a/tests/ui/needless_option_take.stderr +++ b/tests/ui/needless_option_take.stderr @@ -1,11 +1,76 @@ error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:12:5 + --> tests/ui/needless_option_take.rs:23:5 | LL | x.as_ref().take(); - | ^^^^^^^^^^^^^^^^^ help: try: `x.as_ref()` + | ^^^^^^^^^^^^^^^^^ | + = note: `as_ref` creates a temporary value, so calling take() has no effect = note: `-D clippy::needless-option-take` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_option_take)]` -error: aborting due to 1 previous error +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:31:13 + | +LL | let y = x.as_mut().take(); + | ^^^^^^^^^^^^^^^^^ + | + = note: `as_mut` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:33:13 + | +LL | let y = x.replace(289).take(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `replace` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:36:13 + | +LL | let y = Some(3).as_mut().take(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `as_mut` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:39:13 + | +LL | let y = Option::as_mut(&mut x).take(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `as_mut` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:43:13 + | +LL | let x = return_option().take(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `return_option` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:47:13 + | +LL | let x = MyStruct::get_option().take(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `get_option` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:53:13 + | +LL | let y = my_vec.first().take(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `first` creates a temporary value, so calling take() has no effect + +error: called `Option::take()` on a temporary value + --> tests/ui/needless_option_take.rs:56:13 + | +LL | let y = my_vec.first().take(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `first` creates a temporary value, so calling take() has no effect + +error: aborting due to 9 previous errors diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed index c25c2062aceba..9864dd2550b62 100644 --- a/tests/ui/precedence.fixed +++ b/tests/ui/precedence.fixed @@ -20,6 +20,10 @@ fn main() { 1 ^ (1 - 1); 3 | (2 - 1); 3 & (5 - 2); + 0x0F00 & (0x00F0 << 4); + 0x0F00 & (0xF000 >> 4); + (0x0F00 << 1) ^ 3; + (0x0F00 << 1) | 2; let b = 3; trip!(b * 8); diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index dc242ecf4c72e..9ef5c43833f88 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -20,6 +20,10 @@ fn main() { 1 ^ 1 - 1; 3 | 2 - 1; 3 & 5 - 2; + 0x0F00 & 0x00F0 << 4; + 0x0F00 & 0xF000 >> 4; + 0x0F00 << 1 ^ 3; + 0x0F00 << 1 | 2; let b = 3; trip!(b * 8); diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index 8057c25a5e499..0d63e827d66ea 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -43,5 +43,29 @@ error: operator precedence can trip the unwary LL | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` -error: aborting due to 7 previous errors +error: operator precedence can trip the unwary + --> tests/ui/precedence.rs:23:5 + | +LL | 0x0F00 & 0x00F0 << 4; + | ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0x00F0 << 4)` + +error: operator precedence can trip the unwary + --> tests/ui/precedence.rs:24:5 + | +LL | 0x0F00 & 0xF000 >> 4; + | ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)` + +error: operator precedence can trip the unwary + --> tests/ui/precedence.rs:25:5 + | +LL | 0x0F00 << 1 ^ 3; + | ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3` + +error: operator precedence can trip the unwary + --> tests/ui/precedence.rs:26:5 + | +LL | 0x0F00 << 1 | 2; + | ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) | 2` + +error: aborting due to 11 previous errors diff --git a/tests/ui/print_literal.fixed b/tests/ui/print_literal.fixed index a7157c07f8a98..1705a7ff01bb4 100644 --- a/tests/ui/print_literal.fixed +++ b/tests/ui/print_literal.fixed @@ -1,5 +1,5 @@ #![warn(clippy::print_literal)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::literal_string_with_formatting_args)] fn main() { // these should be fine diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 4b04b42744ccd..d10b26b5887cc 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -1,5 +1,5 @@ #![warn(clippy::print_literal)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::literal_string_with_formatting_args)] fn main() { // these should be fine diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 47149622ef7c6..47d6e119543d1 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -15,6 +15,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::manual_find_map)] #![allow(clippy::manual_filter_map)] +#![allow(unpredictable_function_pointer_comparisons)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 7a78a5d280ddb..12c7db69be2e4 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -15,6 +15,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::manual_find_map)] #![allow(clippy::manual_filter_map)] +#![allow(unpredictable_function_pointer_comparisons)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index dc24bc16d0ea4..1ec45c4f1f7ba 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> tests/ui/rename.rs:64:9 + --> tests/ui/rename.rs:65:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,397 +8,397 @@ LL | #![warn(clippy::almost_complete_letter_range)] = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> tests/ui/rename.rs:65:9 + --> tests/ui/rename.rs:66:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:66:9 + --> tests/ui/rename.rs:67:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:67:9 + --> tests/ui/rename.rs:68:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::blocks_in_if_conditions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:71:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:71:9 + --> tests/ui/rename.rs:72:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:72:9 + --> tests/ui/rename.rs:73:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:73:9 + --> tests/ui/rename.rs:74:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:75:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:76:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::find_map)] | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::filter_map)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` - --> tests/ui/rename.rs:78:9 + --> tests/ui/rename.rs:79:9 | LL | #![warn(clippy::fn_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> tests/ui/rename.rs:79:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:81:9 | LL | #![warn(clippy::if_let_redundant_pattern_matching)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:81:9 + --> tests/ui/rename.rs:82:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> tests/ui/rename.rs:82:9 + --> tests/ui/rename.rs:83:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> tests/ui/rename.rs:83:9 + --> tests/ui/rename.rs:84:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:85:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> tests/ui/rename.rs:86:9 + --> tests/ui/rename.rs:87:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> tests/ui/rename.rs:87:9 + --> tests/ui/rename.rs:88:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:88:9 + --> tests/ui/rename.rs:89:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:89:9 + --> tests/ui/rename.rs:90:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:90:9 + --> tests/ui/rename.rs:91:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:91:9 + --> tests/ui/rename.rs:92:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::overflow_check_conditional)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> tests/ui/rename.rs:93:9 + --> tests/ui/rename.rs:94:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:96:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:96:9 + --> tests/ui/rename.rs:97:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:97:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> tests/ui/rename.rs:98:9 + --> tests/ui/rename.rs:99:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` - --> tests/ui/rename.rs:99:9 + --> tests/ui/rename.rs:100:9 | LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> tests/ui/rename.rs:100:9 + --> tests/ui/rename.rs:101:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> tests/ui/rename.rs:101:9 + --> tests/ui/rename.rs:102:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> tests/ui/rename.rs:102:9 + --> tests/ui/rename.rs:103:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> tests/ui/rename.rs:103:9 + --> tests/ui/rename.rs:104:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> tests/ui/rename.rs:104:9 + --> tests/ui/rename.rs:105:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:106:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:107:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:108:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> tests/ui/rename.rs:114:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> tests/ui/rename.rs:115:9 + --> tests/ui/rename.rs:116:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> tests/ui/rename.rs:116:9 + --> tests/ui/rename.rs:117:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> tests/ui/rename.rs:117:9 + --> tests/ui/rename.rs:118:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> tests/ui/rename.rs:118:9 + --> tests/ui/rename.rs:119:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:119:9 + --> tests/ui/rename.rs:120:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` - --> tests/ui/rename.rs:120:9 + --> tests/ui/rename.rs:121:9 | LL | #![warn(clippy::maybe_misused_cfg)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:121:9 + --> tests/ui/rename.rs:122:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` - --> tests/ui/rename.rs:122:9 + --> tests/ui/rename.rs:123:9 | LL | #![warn(clippy::mismatched_target_os)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:123:9 + --> tests/ui/rename.rs:124:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:124:9 + --> tests/ui/rename.rs:125:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` - --> tests/ui/rename.rs:125:9 + --> tests/ui/rename.rs:126:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:126:9 + --> tests/ui/rename.rs:127:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:127:9 + --> tests/ui/rename.rs:128:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:128:9 + --> tests/ui/rename.rs:129:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:129:9 + --> tests/ui/rename.rs:130:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` - --> tests/ui/rename.rs:130:9 + --> tests/ui/rename.rs:131:9 | LL | #![warn(clippy::reverse_range_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` diff --git a/tests/ui/repr_packed_without_abi.rs b/tests/ui/repr_packed_without_abi.rs new file mode 100644 index 0000000000000..16b5ededee990 --- /dev/null +++ b/tests/ui/repr_packed_without_abi.rs @@ -0,0 +1,37 @@ +#![deny(clippy::repr_packed_without_abi)] + +#[repr(packed)] +struct NetworkPacketHeader { + header_length: u8, + header_version: u16, +} + +#[repr(packed)] +union Foo { + a: u8, + b: u16, +} + +#[repr(C, packed)] +struct NoLintCNetworkPacketHeader { + header_length: u8, + header_version: u16, +} + +#[repr(Rust, packed)] +struct NoLintRustNetworkPacketHeader { + header_length: u8, + header_version: u16, +} + +#[repr(packed, C)] +union NotLintCFoo { + a: u8, + b: u16, +} + +#[repr(packed, Rust)] +union NotLintRustFoo { + a: u8, + b: u16, +} diff --git a/tests/ui/repr_packed_without_abi.stderr b/tests/ui/repr_packed_without_abi.stderr new file mode 100644 index 0000000000000..4f7acd00db3d8 --- /dev/null +++ b/tests/ui/repr_packed_without_abi.stderr @@ -0,0 +1,35 @@ +error: item uses `packed` representation without ABI-qualification + --> tests/ui/repr_packed_without_abi.rs:4:1 + | +LL | #[repr(packed)] + | ------ `packed` representation set here +LL | / struct NetworkPacketHeader { +LL | | header_length: u8, +LL | | header_version: u16, +LL | | } + | |_^ + | + = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI + = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]` +note: the lint level is defined here + --> tests/ui/repr_packed_without_abi.rs:1:9 + | +LL | #![deny(clippy::repr_packed_without_abi)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: item uses `packed` representation without ABI-qualification + --> tests/ui/repr_packed_without_abi.rs:10:1 + | +LL | #[repr(packed)] + | ------ `packed` representation set here +LL | / union Foo { +LL | | a: u8, +LL | | b: u16, +LL | | } + | |_^ + | + = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI + = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/result_unit_error_no_std.rs b/tests/ui/result_unit_error_no_std.rs new file mode 100644 index 0000000000000..1e7a028a7fc02 --- /dev/null +++ b/tests/ui/result_unit_error_no_std.rs @@ -0,0 +1,26 @@ +#![feature(lang_items, start, libc)] +#![no_std] +#![warn(clippy::result_unit_err)] + +#[clippy::msrv = "1.80"] +pub fn returns_unit_error_no_lint() -> Result { + Err(()) +} + +#[clippy::msrv = "1.81"] +pub fn returns_unit_error_lint() -> Result { + Err(()) +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} diff --git a/tests/ui/result_unit_error_no_std.stderr b/tests/ui/result_unit_error_no_std.stderr new file mode 100644 index 0000000000000..33692e6055438 --- /dev/null +++ b/tests/ui/result_unit_error_no_std.stderr @@ -0,0 +1,12 @@ +error: this returns a `Result<_, ()>` + --> tests/ui/result_unit_error_no_std.rs:11:1 + | +LL | pub fn returns_unit_error_lint() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a custom `Error` type instead + = note: `-D clippy::result-unit-err` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_unit_err)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 258dba9dd831e..31944f5ef1b1d 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -119,4 +119,26 @@ fn ice_8748() { }]; } +// https://github.com/rust-lang/rust-clippy/issues/10780 +fn shadow_closure() { + // These are not shadow_unrelated; but they are correctly shadow_reuse + let x = Some(1); + #[allow(clippy::shadow_reuse)] + let y = x.map(|x| x + 1); + let z = x.map(|x| x + 1); + let a: Vec> = [100u8, 120, 140] + .iter() + .map(|i| i.checked_mul(2)) + .map(|i| i.map(|i| i - 10)) + .collect(); +} + +struct Issue13795 { + value: i32, +} + +fn issue13795(value: Issue13795) { + let Issue13795 { value, .. } = value; +} + fn main() {} diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index fdd149a2216f2..c8c524b3a2f58 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -280,5 +280,41 @@ note: previous binding is here LL | let x = 1; | ^ -error: aborting due to 23 previous errors +error: `x` is shadowed + --> tests/ui/shadow.rs:128:20 + | +LL | let z = x.map(|x| x + 1); + | ^ + | +note: previous binding is here + --> tests/ui/shadow.rs:125:9 + | +LL | let x = Some(1); + | ^ + +error: `i` is shadowed + --> tests/ui/shadow.rs:132:25 + | +LL | .map(|i| i.map(|i| i - 10)) + | ^ + | +note: previous binding is here + --> tests/ui/shadow.rs:132:15 + | +LL | .map(|i| i.map(|i| i - 10)) + | ^ + +error: `value` is shadowed by itself in `value` + --> tests/ui/shadow.rs:141:22 + | +LL | let Issue13795 { value, .. } = value; + | ^^^^^ + | +note: previous binding is here + --> tests/ui/shadow.rs:140:15 + | +LL | fn issue13795(value: Issue13795) { + | ^^^^^ + +error: aborting due to 26 previous errors diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed new file mode 100644 index 0000000000000..ed05f6e0c8d35 --- /dev/null +++ b/tests/ui/significant_drop_tightening.fixed @@ -0,0 +1,144 @@ +#![warn(clippy::significant_drop_tightening)] + +use std::sync::Mutex; + +pub fn complex_return_triggers_the_lint() -> i32 { + fn foo() -> i32 { + 1 + } + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let _ = *lock; + let _ = *lock; + drop(lock); + foo() +} + +pub fn issue_10413() { + let mutex = Mutex::new(Some(1)); + let opt = Some(1); + if opt.is_some() { + let lock = mutex.lock().unwrap(); + let _ = *lock; + if opt.is_some() { + let _ = *lock; + } + } +} + +pub fn issue_11128() { + use std::mem::drop as unlock; + + struct Foo { + droppable: Option>, + mutex: Mutex>, + } + + impl Drop for Foo { + fn drop(&mut self) { + if let Some(droppable) = self.droppable.take() { + let lock = self.mutex.lock().unwrap(); + let idx_opt = lock.iter().copied().find(|el| Some(el) == droppable.first()); + if let Some(idx) = idx_opt { + let local_droppable = vec![lock.first().copied().unwrap_or_default()]; + unlock(lock); + drop(local_droppable); + } + } + } + } +} + +pub fn issue_11160() -> bool { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + true +} + +pub fn issue_11189() { + struct Number { + pub value: u32, + } + + fn do_something() -> Result<(), ()> { + let number = Mutex::new(Number { value: 1 }); + let number2 = Mutex::new(Number { value: 2 }); + let number3 = Mutex::new(Number { value: 3 }); + let mut lock = number.lock().unwrap(); + let mut lock2 = number2.lock().unwrap(); + let mut lock3 = number3.lock().unwrap(); + lock.value += 1; + lock2.value += 1; + lock3.value += 1; + drop((lock, lock2, lock3)); + Ok(()) + } +} + +pub fn path_return_can_be_ignored() -> i32 { + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let rslt = *lock; + let _ = *lock; + rslt +} + +pub fn post_bindings_can_be_ignored() { + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let rslt = *lock; + let another = rslt; + let _ = another; +} + +pub fn unnecessary_contention_with_multiple_owned_results() { + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + let _ = lock.is_positive(); + } + + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let rslt0 = lock.abs(); + let rslt1 = lock.is_positive(); + drop(lock); + do_heavy_computation_that_takes_time((rslt0, rslt1)); + } +} + +pub fn unnecessary_contention_with_single_owned_results() { + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + } + { + let mutex = Mutex::new(vec![1i32]); + let mut lock = mutex.lock().unwrap(); + lock.clear(); + } + + { + let mutex = Mutex::new(1i32); + + let rslt0 = mutex.lock().unwrap().abs(); + + do_heavy_computation_that_takes_time(rslt0); + } + { + let mutex = Mutex::new(vec![1i32]); + + mutex.lock().unwrap().clear(); + + do_heavy_computation_that_takes_time(()); + } +} + +// Marker used for illustration purposes. +pub fn do_heavy_computation_that_takes_time(_: T) {} + +fn main() {} diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index 77538167548ec..e5f17278f0f6a 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -1,7 +1,5 @@ #![warn(clippy::significant_drop_tightening)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::sync::Mutex; pub fn complex_return_triggers_the_lint() -> i32 { diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index 7d7e3ac7d0ae2..aef774a3d3600 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:12:9 + --> tests/ui/significant_drop_tightening.rs:10:9 | LL | pub fn complex_return_triggers_the_lint() -> i32 { | __________________________________________________- @@ -23,7 +23,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:106:13 + --> tests/ui/significant_drop_tightening.rs:104:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -43,7 +43,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:127:13 + --> tests/ui/significant_drop_tightening.rs:125:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -59,14 +59,11 @@ help: merge the temporary construction with its single usage | LL ~ LL + let rslt0 = mutex.lock().unwrap().abs(); - | -help: remove separated single usage - | -LL - let rslt0 = lock.abs(); +LL ~ | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:133:17 + --> tests/ui/significant_drop_tightening.rs:131:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); @@ -82,10 +79,7 @@ help: merge the temporary construction with its single usage | LL ~ LL + mutex.lock().unwrap().clear(); - | -help: remove separated single usage - | -LL - lock.clear(); +LL ~ | error: aborting due to 4 previous errors diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 4016b2699d6b4..d3d5fd8b35c87 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -17,7 +17,13 @@ fn single_match() { }; let x = Some(1u8); - if let Some(y) = x { println!("{:?}", y) } + match x { + // Note the missing block braces. + // We suggest `if let Some(y) = x { .. }` because the macro + // is expanded before we can do anything. + Some(y) => println!("{:?}", y), + _ => (), + } let z = (1u8, 1u8); if let (2..=3, 7..=9) = z { dummy() }; @@ -297,6 +303,10 @@ fn issue11365() { if let Some(A | B) = &Some(A) { println!() } } +fn issue12758(s: &[u8]) { + if &s[0..3] == b"foo" { println!() } +} + #[derive(Eq, PartialEq)] pub struct Data([u8; 4]); @@ -318,5 +328,25 @@ fn irrefutable_match() { - println!() + println!(); + + let mut x = vec![1i8]; + + // Should not lint. + match x.pop() { + // bla + Some(u) => println!("{u}"), + // more comments! + None => {}, + } + // Should not lint. + match x.pop() { + // bla + Some(u) => { + // bla + println!("{u}"); + }, + // bla + None => {}, + } } diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 75edaa606053d..2f3547c50639d 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -361,6 +361,13 @@ fn issue11365() { } } +fn issue12758(s: &[u8]) { + match &s[0..3] { + b"foo" => println!(), + _ => {}, + } +} + #[derive(Eq, PartialEq)] pub struct Data([u8; 4]); @@ -401,4 +408,24 @@ fn irrefutable_match() { CONST_I32 => println!(), _ => {}, } + + let mut x = vec![1i8]; + + // Should not lint. + match x.pop() { + // bla + Some(u) => println!("{u}"), + // more comments! + None => {}, + } + // Should not lint. + match x.pop() { + // bla + Some(u) => { + // bla + println!("{u}"); + }, + // bla + None => {}, + } } diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index dd03737279ad1..54bbfbac093c2 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -18,15 +18,6 @@ LL + println!("{:?}", y); LL ~ }; | -error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:23:5 - | -LL | / match x { -... | -LL | | _ => (), -LL | | } - | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }` - error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> tests/ui/single_match.rs:32:5 | @@ -213,8 +204,17 @@ LL | | None | Some(_) => {}, LL | | } | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }` +error: you seem to be trying to use `match` for an equality check. Consider using `if` + --> tests/ui/single_match.rs:365:5 + | +LL | / match &s[0..3] { +LL | | b"foo" => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `if &s[0..3] == b"foo" { println!() }` + error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:371:5 + --> tests/ui/single_match.rs:378:5 | LL | / match DATA { LL | | DATA => println!(), @@ -223,7 +223,7 @@ LL | | } | |_____^ help: try: `println!();` error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:376:5 + --> tests/ui/single_match.rs:383:5 | LL | / match CONST_I32 { LL | | CONST_I32 => println!(), @@ -232,7 +232,7 @@ LL | | } | |_____^ help: try: `println!();` error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:382:5 + --> tests/ui/single_match.rs:389:5 | LL | / match i { LL | | i => { @@ -252,7 +252,7 @@ LL + } | error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:390:5 + --> tests/ui/single_match.rs:397:5 | LL | / match i { LL | | i => {}, @@ -261,7 +261,7 @@ LL | | } | |_____^ help: `match` expression can be removed error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:395:5 + --> tests/ui/single_match.rs:402:5 | LL | / match i { LL | | i => (), @@ -270,13 +270,13 @@ LL | | } | |_____^ help: `match` expression can be removed error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:400:5 + --> tests/ui/single_match.rs:407:5 | LL | / match CONST_I32 { LL | | CONST_I32 => println!(), LL | | _ => {}, LL | | } - | |_____^ help: try: `println!()` + | |_____^ help: try: `println!();` error: aborting due to 26 previous errors diff --git a/tests/ui/trailing_empty_array.rs b/tests/ui/trailing_empty_array.rs index 3d06c2621681d..309a5920dfdeb 100644 --- a/tests/ui/trailing_empty_array.rs +++ b/tests/ui/trailing_empty_array.rs @@ -1,4 +1,5 @@ #![warn(clippy::trailing_empty_array)] +#![allow(clippy::repr_packed_without_abi)] // Do lint: diff --git a/tests/ui/trailing_empty_array.stderr b/tests/ui/trailing_empty_array.stderr index 756381478f2b7..7ebff372cf759 100644 --- a/tests/ui/trailing_empty_array.stderr +++ b/tests/ui/trailing_empty_array.stderr @@ -1,5 +1,5 @@ error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:5:1 + --> tests/ui/trailing_empty_array.rs:6:1 | LL | / struct RarelyUseful { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::trailing_empty_array)]` error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:11:1 + --> tests/ui/trailing_empty_array.rs:12:1 | LL | / struct OnlyField { LL | | @@ -24,7 +24,7 @@ LL | | } = help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:16:1 + --> tests/ui/trailing_empty_array.rs:17:1 | LL | / struct GenericArrayType { LL | | @@ -36,7 +36,7 @@ LL | | } = help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:23:1 + --> tests/ui/trailing_empty_array.rs:24:1 | LL | / struct OnlyAnotherAttribute { LL | | @@ -48,7 +48,7 @@ LL | | } = help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:30:1 + --> tests/ui/trailing_empty_array.rs:31:1 | LL | / struct OnlyADeriveAttribute { LL | | @@ -60,7 +60,7 @@ LL | | } = help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:37:1 + --> tests/ui/trailing_empty_array.rs:38:1 | LL | / struct ZeroSizedWithConst { LL | | @@ -72,7 +72,7 @@ LL | | } = help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:47:1 + --> tests/ui/trailing_empty_array.rs:48:1 | LL | / struct ZeroSizedWithConstFunction { LL | | @@ -84,7 +84,7 @@ LL | | } = help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:56:1 + --> tests/ui/trailing_empty_array.rs:57:1 | LL | / struct ZeroSizedWithConstFunction2 { LL | | @@ -96,7 +96,7 @@ LL | | } = help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:62:1 + --> tests/ui/trailing_empty_array.rs:63:1 | LL | struct ZeroSizedArrayWrapper([usize; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | struct ZeroSizedArrayWrapper([usize; 0]); = help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:65:1 + --> tests/ui/trailing_empty_array.rs:66:1 | LL | struct TupleStruct(i32, [usize; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | struct TupleStruct(i32, [usize; 0]); = help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> tests/ui/trailing_empty_array.rs:68:1 + --> tests/ui/trailing_empty_array.rs:69:1 | LL | / struct LotsOfFields { LL | | diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed index f0d570efdcee7..9911d1317070a 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -3,6 +3,7 @@ //@[edition2021] edition:2021 #![warn(clippy::uninlined_format_args)] +#![allow(clippy::literal_string_with_formatting_args)] fn main() { let var = 1; diff --git a/tests/ui/uninlined_format_args_panic.edition2018.stderr b/tests/ui/uninlined_format_args_panic.edition2018.stderr index 0541dd9a7d7bc..4b154abac5bc0 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.stderr +++ b/tests/ui/uninlined_format_args_panic.edition2018.stderr @@ -1,5 +1,5 @@ error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:10:5 + --> tests/ui/uninlined_format_args_panic.rs:11:5 | LL | println!("val='{}'", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed index 7c0f28c457642..87b74670565f4 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -3,6 +3,7 @@ //@[edition2021] edition:2021 #![warn(clippy::uninlined_format_args)] +#![allow(clippy::literal_string_with_formatting_args)] fn main() { let var = 1; diff --git a/tests/ui/uninlined_format_args_panic.edition2021.stderr b/tests/ui/uninlined_format_args_panic.edition2021.stderr index 3615eaa9dee37..7638d3f8bbadc 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.stderr +++ b/tests/ui/uninlined_format_args_panic.edition2021.stderr @@ -1,5 +1,5 @@ error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:10:5 + --> tests/ui/uninlined_format_args_panic.rs:11:5 | LL | println!("val='{}'", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + println!("val='{var}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:13:9 + --> tests/ui/uninlined_format_args_panic.rs:14:9 | LL | panic!("p1 {}", var); | ^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + panic!("p1 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:16:9 + --> tests/ui/uninlined_format_args_panic.rs:17:9 | LL | panic!("p2 {0}", var); | ^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + panic!("p2 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:19:9 + --> tests/ui/uninlined_format_args_panic.rs:20:9 | LL | panic!("p3 {var}", var = var); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + panic!("p3 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:29:5 + --> tests/ui/uninlined_format_args_panic.rs:30:5 | LL | assert!(var == 1, "p5 {}", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + assert!(var == 1, "p5 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:30:5 + --> tests/ui/uninlined_format_args_panic.rs:31:5 | LL | debug_assert!(var == 1, "p6 {}", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs index fa594d9a96f0f..647c69bc5c410 100644 --- a/tests/ui/uninlined_format_args_panic.rs +++ b/tests/ui/uninlined_format_args_panic.rs @@ -3,6 +3,7 @@ //@[edition2021] edition:2021 #![warn(clippy::uninlined_format_args)] +#![allow(clippy::literal_string_with_formatting_args)] fn main() { let var = 1; diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed new file mode 100644 index 0000000000000..dc5e163ff04e4 --- /dev/null +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -0,0 +1,201 @@ +#![allow(unused_assignments)] +#![warn(clippy::unnecessary_to_owned)] + +#[allow(dead_code)] +#[derive(Clone, Copy)] +enum FileType { + Account, + PrivateKey, + Certificate, +} + +fn main() { + let path = std::path::Path::new("x"); + + let _ = check_files(&[(FileType::Account, path)]); + let _ = check_files_vec(vec![(FileType::Account, path)]); + + // negative tests + let _ = check_files_ref(&[(FileType::Account, path)]); + let _ = check_files_mut(&[(FileType::Account, path)]); + let _ = check_files_ref_mut(&[(FileType::Account, path)]); + let _ = check_files_self_and_arg(&[(FileType::Account, path)]); + let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); + + check_mut_iteratee_and_modify_inner_variable(); +} + +// `check_files` and its variants are based on: +// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 +fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { + for (t, path) in files { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool { + for (t, path) in files.iter() { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool { + for (ref t, path) in files.iter().copied() { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +#[allow(unused_assignments)] +fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool { + for (mut t, path) in files.iter().copied() { + t = FileType::PrivateKey; + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool { + for (ref mut t, path) in files.iter().copied() { + *t = FileType::PrivateKey; + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool { + for (t, path) in files.iter().copied() { + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.join(path).is_file() || !other.is_file() { + return false; + } + } + true +} + +#[allow(unused_assignments)] +fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { + for (mut t, path) in files.iter().cloned() { + t = FileType::PrivateKey; + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn get_file_path(_file_type: &FileType) -> Result { + Ok(std::path::PathBuf::new()) +} + +// Issue 12098 +// https://github.com/rust-lang/rust-clippy/issues/12098 +// no message emits +fn check_mut_iteratee_and_modify_inner_variable() { + struct Test { + list: Vec, + mut_this: bool, + } + + impl Test { + fn list(&self) -> &[String] { + &self.list + } + } + + let mut test = Test { + list: vec![String::from("foo"), String::from("bar")], + mut_this: false, + }; + + for _item in test.list().to_vec() { + println!("{}", _item); + + test.mut_this = true; + { + test.mut_this = true; + } + } +} + +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 331b7b25271ba..8f797ac717fb6 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -1,8 +1,6 @@ #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - #[allow(dead_code)] #[derive(Clone, Copy)] enum FileType { diff --git a/tests/ui/unnecessary_iter_cloned.stderr b/tests/ui/unnecessary_iter_cloned.stderr index e3592e3cbbd82..6f2ae0ab1f35a 100644 --- a/tests/ui/unnecessary_iter_cloned.stderr +++ b/tests/ui/unnecessary_iter_cloned.stderr @@ -1,71 +1,58 @@ error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:33:22 + --> tests/ui/unnecessary_iter_cloned.rs:31:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` -help: use - | -LL | for (t, path) in files { - | ~~~~~ help: remove any references to the binding | -LL - let other = match get_file_path(&t) { -LL + let other = match get_file_path(t) { +LL ~ for (t, path) in files { +LL ~ let other = match get_file_path(t) { | error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:48:22 + --> tests/ui/unnecessary_iter_cloned.rs:46:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ | -help: use - | -LL | for (t, path) in files.iter() { - | ~~~~~~~~~~~~ help: remove any references to the binding | -LL - let other = match get_file_path(&t) { -LL + let other = match get_file_path(t) { +LL ~ for (t, path) in files.iter() { +LL ~ let other = match get_file_path(t) { | error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:179:18 + --> tests/ui/unnecessary_iter_cloned.rs:177:18 | LL | for c in v.iter().cloned() { - | ^^^^^^^^^^^^^^^^^ help: use: `v.iter()` + | ^^^^^^^^^^^^^^^^^ help: remove any references to the binding: `v.iter()` error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:187:18 + --> 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; +LL ~ for c in v.iter() { +LL | +LL ~ let ref_c = c; | error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:196:23 + --> 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 ~ for (i, c) in v.iter() { +LL | LL ~ let ref_c = c; LL ~ let ref_i = i; | diff --git a/tests/ui/unnecessary_sort_by_no_std.fixed b/tests/ui/unnecessary_sort_by_no_std.fixed new file mode 100644 index 0000000000000..c7be000b820cf --- /dev/null +++ b/tests/ui/unnecessary_sort_by_no_std.fixed @@ -0,0 +1,20 @@ +#![no_std] +extern crate alloc; +use alloc::vec; +use alloc::vec::Vec; + +fn issue_11524() -> Vec { + let mut vec = vec![1, 2, 3]; + + // Should lint and suggest `vec.sort_by_key(|a| a + 1);` + vec.sort_by_key(|a| a + 1); + vec +} + +fn issue_11524_2() -> Vec { + let mut vec = vec![1, 2, 3]; + + // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` + vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); + vec +} diff --git a/tests/ui/unnecessary_sort_by_no_std.rs b/tests/ui/unnecessary_sort_by_no_std.rs new file mode 100644 index 0000000000000..5f44be97c61f5 --- /dev/null +++ b/tests/ui/unnecessary_sort_by_no_std.rs @@ -0,0 +1,20 @@ +#![no_std] +extern crate alloc; +use alloc::vec; +use alloc::vec::Vec; + +fn issue_11524() -> Vec { + let mut vec = vec![1, 2, 3]; + + // Should lint and suggest `vec.sort_by_key(|a| a + 1);` + vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); + vec +} + +fn issue_11524_2() -> Vec { + let mut vec = vec![1, 2, 3]; + + // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` + vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); + vec +} diff --git a/tests/ui/unnecessary_sort_by_no_std.stderr b/tests/ui/unnecessary_sort_by_no_std.stderr new file mode 100644 index 0000000000000..a57fbc7a6328c --- /dev/null +++ b/tests/ui/unnecessary_sort_by_no_std.stderr @@ -0,0 +1,17 @@ +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by_no_std.rs:10:5 + | +LL | vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| a + 1)` + | + = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by_no_std.rs:18:5 + | +LL | vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| core::cmp::Reverse(b + 1))` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed new file mode 100644 index 0000000000000..fdcac8fb08dcf --- /dev/null +++ b/tests/ui/unnecessary_to_owned.fixed @@ -0,0 +1,587 @@ +#![allow( + clippy::needless_borrow, + clippy::needless_borrows_for_generic_args, + clippy::ptr_arg, + clippy::manual_async_fn, + clippy::needless_lifetimes +)] +#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] + +use std::borrow::Cow; +use std::ffi::{CStr, CString, OsStr, OsString}; +use std::ops::Deref; + +#[derive(Clone)] +struct X(String); + +impl Deref for X { + type Target = [u8]; + fn deref(&self) -> &[u8] { + self.0.as_bytes() + } +} + +impl AsRef for X { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} + +#[allow(clippy::to_string_trait_impl)] +impl ToString for X { + fn to_string(&self) -> String { + self.0.to_string() + } +} + +impl X { + fn join(&self, other: impl AsRef) -> Self { + let mut s = self.0.clone(); + s.push_str(other.as_ref()); + Self(s) + } +} + +#[allow(dead_code)] +#[derive(Clone)] +enum FileType { + Account, + PrivateKey, + Certificate, +} + +fn main() { + let c_str = CStr::from_bytes_with_nul(&[0]).unwrap(); + let os_str = OsStr::new("x"); + let path = std::path::Path::new("x"); + let s = "x"; + let array = ["x"]; + let array_ref = &["x"]; + let slice = &["x"][..]; + let x = X(String::from("x")); + let x_ref = &x; + + require_c_str(&Cow::from(c_str)); + require_c_str(c_str); + + require_os_str(os_str); + require_os_str(&Cow::from(os_str)); + require_os_str(os_str); + + require_path(path); + require_path(&Cow::from(path)); + require_path(path); + + require_str(s); + require_str(&Cow::from(s)); + require_str(s); + require_str(x_ref.as_ref()); + + require_slice(slice); + require_slice(&Cow::from(slice)); + require_slice(array.as_ref()); + require_slice(array_ref.as_ref()); + require_slice(slice); + require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. + + require_x(&Cow::::Owned(x.clone())); + require_x(&x_ref.to_owned()); // No longer flagged because of #8759. + + require_deref_c_str(c_str); + require_deref_os_str(os_str); + require_deref_path(path); + require_deref_str(s); + require_deref_slice(slice); + + require_impl_deref_c_str(c_str); + require_impl_deref_os_str(os_str); + require_impl_deref_path(path); + require_impl_deref_str(s); + require_impl_deref_slice(slice); + + require_deref_str_slice(s, slice); + require_deref_slice_str(slice, s); + + require_as_ref_c_str(c_str); + require_as_ref_os_str(os_str); + require_as_ref_path(path); + require_as_ref_str(s); + require_as_ref_str(&x); + require_as_ref_slice(array); + require_as_ref_slice(array_ref); + require_as_ref_slice(slice); + + require_impl_as_ref_c_str(c_str); + require_impl_as_ref_os_str(os_str); + require_impl_as_ref_path(path); + require_impl_as_ref_str(s); + require_impl_as_ref_str(&x); + require_impl_as_ref_slice(array); + require_impl_as_ref_slice(array_ref); + require_impl_as_ref_slice(slice); + + require_as_ref_str_slice(s, array); + require_as_ref_str_slice(s, array_ref); + require_as_ref_str_slice(s, slice); + require_as_ref_slice_str(array, s); + require_as_ref_slice_str(array_ref, s); + require_as_ref_slice_str(slice, s); + + let _ = x.join(x_ref); + + let _ = slice.iter().copied(); + let _ = slice.iter().copied(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + + let _ = slice.iter().copied(); + let _ = slice.iter().copied(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + + let _ = check_files(&[FileType::Account]); + + // negative tests + require_string(&s.to_string()); + require_string(&Cow::from(s).into_owned()); + require_string(&s.to_owned()); + require_string(&x_ref.to_string()); + + // `X` isn't copy. + require_slice(&x.to_owned()); + require_deref_slice(x.to_owned()); + + // The following should be flagged by `redundant_clone`, but not by this lint. + require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap()); + require_os_str(&OsString::from("x")); + require_path(&std::path::PathBuf::from("x")); + require_str(&String::from("x")); + require_slice(&[String::from("x")]); + + let slice = [0u8; 1024]; + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); +} + +fn require_c_str(_: &CStr) {} +fn require_os_str(_: &OsStr) {} +fn require_path(_: &std::path::Path) {} +fn require_str(_: &str) {} +fn require_slice(_: &[T]) {} +fn require_x(_: &X) {} + +fn require_deref_c_str>(_: T) {} +fn require_deref_os_str>(_: T) {} +fn require_deref_path>(_: T) {} +fn require_deref_str>(_: T) {} +fn require_deref_slice>(_: U) {} + +fn require_impl_deref_c_str(_: impl Deref) {} +fn require_impl_deref_os_str(_: impl Deref) {} +fn require_impl_deref_path(_: impl Deref) {} +fn require_impl_deref_str(_: impl Deref) {} +fn require_impl_deref_slice(_: impl Deref) {} + +fn require_deref_str_slice, U, V: Deref>(_: T, _: V) {} +fn require_deref_slice_str, V: Deref>(_: U, _: V) {} + +fn require_as_ref_c_str>(_: T) {} +fn require_as_ref_os_str>(_: T) {} +fn require_as_ref_path>(_: T) {} +fn require_as_ref_str>(_: T) {} +fn require_as_ref_slice>(_: U) {} + +fn require_impl_as_ref_c_str(_: impl AsRef) {} +fn require_impl_as_ref_os_str(_: impl AsRef) {} +fn require_impl_as_ref_path(_: impl AsRef) {} +fn require_impl_as_ref_str(_: impl AsRef) {} +fn require_impl_as_ref_slice(_: impl AsRef<[T]>) {} + +fn require_as_ref_str_slice, U, V: AsRef<[U]>>(_: T, _: V) {} +fn require_as_ref_slice_str, V: AsRef>(_: U, _: V) {} + +// `check_files` is based on: +// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 +fn check_files(file_types: &[FileType]) -> bool { + for t in file_types { + let path = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() { + return false; + } + } + true +} + +fn get_file_path(_file_type: &FileType) -> Result { + Ok(std::path::PathBuf::new()) +} + +fn require_string(_: &String) {} + +#[clippy::msrv = "1.35"] +fn _msrv_1_35() { + // `copied` was stabilized in 1.36, so clippy should use `cloned`. + let _ = &["x"][..].iter().cloned(); +} + +#[clippy::msrv = "1.36"] +fn _msrv_1_36() { + let _ = &["x"][..].iter().copied(); +} + +// https://github.com/rust-lang/rust-clippy/issues/8507 +mod issue_8507 { + #![allow(dead_code)] + + struct Opaque

(P); + + pub trait Abstracted {} + + impl

Abstracted for Opaque

{} + + fn build

(p: P) -> Opaque

+ where + P: AsRef, + { + Opaque(p) + } + + // Should not lint. + fn test_str(s: &str) -> Box { + Box::new(build(s.to_string())) + } + + // Should not lint. + fn test_x(x: super::X) -> Box { + Box::new(build(x)) + } + + #[derive(Clone, Copy)] + struct Y(&'static str); + + impl AsRef for Y { + fn as_ref(&self) -> &str { + self.0 + } + } + + #[allow(clippy::to_string_trait_impl)] + impl ToString for Y { + fn to_string(&self) -> String { + self.0.to_string() + } + } + + // Should lint because Y is copy. + fn test_y(y: Y) -> Box { + Box::new(build(y)) + } +} + +// https://github.com/rust-lang/rust-clippy/issues/8759 +mod issue_8759 { + #![allow(dead_code)] + + #[derive(Default)] + struct View {} + + impl std::borrow::ToOwned for View { + type Owned = View; + fn to_owned(&self) -> Self::Owned { + View {} + } + } + + #[derive(Default)] + struct RenderWindow { + default_view: View, + } + + impl RenderWindow { + fn default_view(&self) -> &View { + &self.default_view + } + fn set_view(&mut self, _view: &View) {} + } + + fn main() { + let mut rw = RenderWindow::default(); + rw.set_view(&rw.default_view().to_owned()); + } +} + +mod issue_8759_variant { + #![allow(dead_code)] + + #[derive(Clone, Default)] + struct View {} + + #[derive(Default)] + struct RenderWindow { + default_view: View, + } + + impl RenderWindow { + fn default_view(&self) -> &View { + &self.default_view + } + fn set_view(&mut self, _view: &View) {} + } + + fn main() { + let mut rw = RenderWindow::default(); + rw.set_view(&rw.default_view().to_owned()); + } +} + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + #[allow(clippy::to_string_trait_impl)] + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc") + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} + +mod issue_9504 { + #![allow(dead_code)] + + async fn foo>(_: S) {} + async fn bar() { + foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; + } +} + +mod issue_9771a { + #![allow(dead_code)] + + use std::marker::PhantomData; + + pub struct Key, V: ?Sized>(K, PhantomData); + + impl, V: ?Sized> Key { + pub fn new(key: K) -> Key { + Key(key, PhantomData) + } + } + + pub fn pkh(pkh: &[u8]) -> Key, String> { + Key::new([b"pkh-", pkh].concat().to_vec()) + } +} + +mod issue_9771b { + #![allow(dead_code)] + + pub struct Key>(K); + + pub fn from(c: &[u8]) -> Key> { + let v = [c].concat(); + Key(v.to_vec()) + } +} + +// This is a watered down version of the code in: https://github.com/oxigraph/rio +// The ICE is triggered by the call to `to_owned` on this line: +// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116 +mod issue_10021 { + #![allow(unused)] + + pub struct Iri(T); + + impl> Iri { + pub fn parse(iri: T) -> Result { + unimplemented!() + } + } + + pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> { + let base_iri = Iri::parse(url.to_owned())?; + Ok(()) + } +} + +mod issue_10033 { + #![allow(dead_code)] + use std::fmt::Display; + use std::ops::Deref; + + fn _main() { + let f = Foo; + + // Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does + // deref to `str`) + foo(&f.to_string()); + } + + fn foo(s: &str) { + println!("{}", s); + } + + struct Foo; + + impl Deref for Foo { + type Target = str; + + fn deref(&self) -> &Self::Target { + "str" + } + } + + impl Display for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Foo") + } + } +} + +mod issue_11952 { + use core::future::{Future, IntoFuture}; + + fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future> { + async move { + let _y = y; + Ok(()) + } + } + + fn bar() { + IntoFuture::into_future(foo([], &0)); + } +} + +fn borrow_checks() { + use std::borrow::Borrow; + use std::collections::HashSet; + + fn inner(a: &[&str]) { + let mut s = HashSet::from([vec!["a"]]); + s.remove(a); //~ ERROR: unnecessary use of `to_vec` + } + + let mut s = HashSet::from(["a".to_string()]); + s.remove("b"); //~ ERROR: unnecessary use of `to_owned` + s.remove("b"); //~ ERROR: unnecessary use of `to_string` + // Should not warn. + s.remove("b"); + + let mut s = HashSet::from([vec!["a"]]); + s.remove(["b"].as_slice()); //~ ERROR: unnecessary use of `to_vec` + s.remove((&["b"]).as_slice()); //~ ERROR: unnecessary use of `to_vec` + + // Should not warn. + s.remove(&["b"].to_vec().clone()); + s.remove(["a"].as_slice()); + + trait SetExt { + fn foo>(&self, _: &String); + } + + impl SetExt for HashSet { + fn foo>(&self, _: &String) {} + } + + // Should not lint! + HashSet::::new().foo::<&str>(&"".to_owned()); + HashSet::::new().get(&1.to_string()); +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index da0c761f795b3..10a9727a9a798 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -7,8 +7,6 @@ )] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; use std::ops::Deref; diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 7ab1f667d9b58..498ac68cdaa0f 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:157:64 + --> tests/ui/unnecessary_to_owned.rs:155:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:157:20 + --> tests/ui/unnecessary_to_owned.rs:155:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()) = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:158:40 + --> tests/ui/unnecessary_to_owned.rs:156:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:158:21 + --> tests/ui/unnecessary_to_owned.rs:156:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:159:48 + --> tests/ui/unnecessary_to_owned.rs:157:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:159:19 + --> tests/ui/unnecessary_to_owned.rs:157:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:160:35 + --> tests/ui/unnecessary_to_owned.rs:158:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:160:18 + --> tests/ui/unnecessary_to_owned.rs:158:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:161:39 + --> tests/ui/unnecessary_to_owned.rs:159:39 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:161:20 + --> tests/ui/unnecessary_to_owned.rs:159:20 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:66:36 + --> tests/ui/unnecessary_to_owned.rs:64:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -70,415 +70,415 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:67:19 + --> tests/ui/unnecessary_to_owned.rs:65:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> tests/ui/unnecessary_to_owned.rs:69:20 + --> tests/ui/unnecessary_to_owned.rs:67:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:70:38 + --> tests/ui/unnecessary_to_owned.rs:68:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:71:20 + --> tests/ui/unnecessary_to_owned.rs:69:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> tests/ui/unnecessary_to_owned.rs:73:18 + --> tests/ui/unnecessary_to_owned.rs:71:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:74:34 + --> tests/ui/unnecessary_to_owned.rs:72:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:75:18 + --> tests/ui/unnecessary_to_owned.rs:73:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:77:17 + --> tests/ui/unnecessary_to_owned.rs:75:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:78:30 + --> tests/ui/unnecessary_to_owned.rs:76:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:79:17 + --> tests/ui/unnecessary_to_owned.rs:77:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:80:17 + --> tests/ui/unnecessary_to_owned.rs:78:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:82:19 + --> tests/ui/unnecessary_to_owned.rs:80:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:83:36 + --> tests/ui/unnecessary_to_owned.rs:81:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:84:19 + --> tests/ui/unnecessary_to_owned.rs:82:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:85:19 + --> tests/ui/unnecessary_to_owned.rs:83:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:86:19 + --> tests/ui/unnecessary_to_owned.rs:84:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:89:42 + --> tests/ui/unnecessary_to_owned.rs:87:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:92:25 + --> tests/ui/unnecessary_to_owned.rs:90:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:93:26 + --> tests/ui/unnecessary_to_owned.rs:91:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:94:24 + --> tests/ui/unnecessary_to_owned.rs:92:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:95:23 + --> tests/ui/unnecessary_to_owned.rs:93:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:96:25 + --> tests/ui/unnecessary_to_owned.rs:94:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:98:30 + --> tests/ui/unnecessary_to_owned.rs:96:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:99:31 + --> tests/ui/unnecessary_to_owned.rs:97:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:100:29 + --> tests/ui/unnecessary_to_owned.rs:98:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:101:28 + --> tests/ui/unnecessary_to_owned.rs:99:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:102:30 + --> tests/ui/unnecessary_to_owned.rs:100:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:104:29 + --> tests/ui/unnecessary_to_owned.rs:102:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:104:43 + --> tests/ui/unnecessary_to_owned.rs:102:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:105:29 + --> tests/ui/unnecessary_to_owned.rs:103:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:105:47 + --> tests/ui/unnecessary_to_owned.rs:103:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:107:26 + --> tests/ui/unnecessary_to_owned.rs:105:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:108:27 + --> tests/ui/unnecessary_to_owned.rs:106:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:109:25 + --> tests/ui/unnecessary_to_owned.rs:107:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:110:24 + --> tests/ui/unnecessary_to_owned.rs:108:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:111:24 + --> tests/ui/unnecessary_to_owned.rs:109:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:112:26 + --> tests/ui/unnecessary_to_owned.rs:110:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:113:26 + --> tests/ui/unnecessary_to_owned.rs:111:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:114:26 + --> tests/ui/unnecessary_to_owned.rs:112:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:116:31 + --> tests/ui/unnecessary_to_owned.rs:114:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:117:32 + --> tests/ui/unnecessary_to_owned.rs:115:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:118:30 + --> tests/ui/unnecessary_to_owned.rs:116:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:119:29 + --> tests/ui/unnecessary_to_owned.rs:117:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:120:29 + --> tests/ui/unnecessary_to_owned.rs:118:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:121:31 + --> tests/ui/unnecessary_to_owned.rs:119:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:122:31 + --> tests/ui/unnecessary_to_owned.rs:120:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:123:31 + --> tests/ui/unnecessary_to_owned.rs:121:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:125:30 + --> tests/ui/unnecessary_to_owned.rs:123:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:125:44 + --> tests/ui/unnecessary_to_owned.rs:123:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:30 + --> tests/ui/unnecessary_to_owned.rs:124:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:44 + --> tests/ui/unnecessary_to_owned.rs:124:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:127:30 + --> tests/ui/unnecessary_to_owned.rs:125:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:127:44 + --> tests/ui/unnecessary_to_owned.rs:125:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:30 + --> tests/ui/unnecessary_to_owned.rs:126:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:48 + --> tests/ui/unnecessary_to_owned.rs:126:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:129:30 + --> tests/ui/unnecessary_to_owned.rs:127:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:129:52 + --> tests/ui/unnecessary_to_owned.rs:127:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:130:30 + --> tests/ui/unnecessary_to_owned.rs:128:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:130:48 + --> tests/ui/unnecessary_to_owned.rs:128:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:132:20 + --> tests/ui/unnecessary_to_owned.rs:130:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:134:13 + --> tests/ui/unnecessary_to_owned.rs:132:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:135:13 + --> tests/ui/unnecessary_to_owned.rs:133:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:136:13 + --> tests/ui/unnecessary_to_owned.rs:134:13 | LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:137:13 + --> tests/ui/unnecessary_to_owned.rs:135:13 | LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:139:13 + --> tests/ui/unnecessary_to_owned.rs:137:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:140:13 + --> tests/ui/unnecessary_to_owned.rs:138:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:141:13 + --> tests/ui/unnecessary_to_owned.rs:139:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:142:13 + --> tests/ui/unnecessary_to_owned.rs:140:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:164:26 + --> tests/ui/unnecessary_to_owned.rs:162:26 | LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -490,7 +490,7 @@ LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:165:26 + --> tests/ui/unnecessary_to_owned.rs:163:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -502,7 +502,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:166:26 + --> tests/ui/unnecessary_to_owned.rs:164:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -514,77 +514,73 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:223:14 + --> tests/ui/unnecessary_to_owned.rs:221:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ | -help: use - | -LL | for t in file_types { - | ~~~~~~~~~~ help: remove any references to the binding | -LL - let path = match get_file_path(&t) { -LL + let path = match get_file_path(t) { +LL ~ for t in file_types { +LL ~ let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:246:14 + --> tests/ui/unnecessary_to_owned.rs:244:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:251:14 + --> tests/ui/unnecessary_to_owned.rs:249:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:299:24 + --> tests/ui/unnecessary_to_owned.rs:297:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:408:12 + --> tests/ui/unnecessary_to_owned.rs:406:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:551:37 + --> tests/ui/unnecessary_to_owned.rs:549:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:561:18 + --> tests/ui/unnecessary_to_owned.rs:559:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:565:14 + --> tests/ui/unnecessary_to_owned.rs:563:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:566:14 + --> tests/ui/unnecessary_to_owned.rs:564:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:571:14 + --> tests/ui/unnecessary_to_owned.rs:569:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:572:14 + --> tests/ui/unnecessary_to_owned.rs:570:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index 231fc0a892ad1..de1062f123b7b 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -134,3 +134,12 @@ pub mod ambiguous_glob_exports { pub use my_prelude::*; pub use my_type::*; } + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/13764 +pub mod unknown_namespace { + pub mod some_module { + pub struct SomeType; + } + #[allow(rustc::non_glob_import_of_type_ir_inherent)] + use some_module::SomeType; +} diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 8dfcd2110a4bb..94657dd1ca378 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -134,3 +134,12 @@ pub mod ambiguous_glob_exports { pub use my_prelude::*; pub use my_type::*; } + +// Regression test for https://github.com/rust-lang/rust-clippy/issues/13764 +pub mod unknown_namespace { + pub mod some_module { + pub struct SomeType; + } + #[allow(rustc::non_glob_import_of_type_ir_inherent)] + use some_module::SomeType; +} diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index eff617a801689..2f7edd92bb7c7 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -3,6 +3,8 @@ // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] +use std::ops::ControlFlow; + fn test_generic(val: T) -> T { let _ = val; val @@ -297,3 +299,46 @@ impl From> for Foo<'b'> { Foo } } + +fn direct_application() { + let _: Result<(), std::io::Error> = test_issue_3913(); + //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913(); + //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913(); + //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913(); + //~^ useless_conversion + + let c: ControlFlow<()> = ControlFlow::Continue(()); + let _: ControlFlow<()> = c; + //~^ useless_conversion + let c: ControlFlow<()> = ControlFlow::Continue(()); + let _: ControlFlow<()> = c; + //~^ useless_conversion + + struct Absorb; + impl From<()> for Absorb { + fn from(_: ()) -> Self { + Self + } + } + impl From for Absorb { + fn from(_: std::io::Error) -> Self { + Self + } + } + let _: Vec = [1u32].into_iter().collect(); + //~^ useless_conversion + + // No lint for those + let _: Result = test_issue_3913().map(Into::into); + let _: Result<(), Absorb> = test_issue_3913().map_err(Into::into); + let _: Result = test_issue_3913().map(From::from); + let _: Result<(), Absorb> = test_issue_3913().map_err(From::from); +} + +fn gen_identity(x: [T; 3]) -> Vec { + x.into_iter().collect() + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 64b0662078919..eacdf77f90520 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -3,6 +3,8 @@ // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] +use std::ops::ControlFlow; + fn test_generic(val: T) -> T { let _ = T::from(val); val.into() @@ -297,3 +299,46 @@ impl From> for Foo<'b'> { Foo } } + +fn direct_application() { + let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); + //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); + //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); + //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); + //~^ useless_conversion + + let c: ControlFlow<()> = ControlFlow::Continue(()); + let _: ControlFlow<()> = c.map_break(Into::into); + //~^ useless_conversion + let c: ControlFlow<()> = ControlFlow::Continue(()); + let _: ControlFlow<()> = c.map_continue(Into::into); + //~^ useless_conversion + + struct Absorb; + impl From<()> for Absorb { + fn from(_: ()) -> Self { + Self + } + } + impl From for Absorb { + fn from(_: std::io::Error) -> Self { + Self + } + } + let _: Vec = [1u32].into_iter().map(Into::into).collect(); + //~^ useless_conversion + + // No lint for those + let _: Result = test_issue_3913().map(Into::into); + let _: Result<(), Absorb> = test_issue_3913().map_err(Into::into); + let _: Result = test_issue_3913().map(From::from); + let _: Result<(), Absorb> = test_issue_3913().map_err(From::from); +} + +fn gen_identity(x: [T; 3]) -> Vec { + x.into_iter().map(Into::into).collect() + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index b149357bcf4f4..6aeb382902ba1 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:7:13 + --> tests/ui/useless_conversion.rs:9:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,220 +11,268 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:8:5 + --> tests/ui/useless_conversion.rs:10:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:20:22 + --> tests/ui/useless_conversion.rs:22:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:50:22 + --> tests/ui/useless_conversion.rs:52:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:55:21 + --> tests/ui/useless_conversion.rs:57:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:61:22 + --> tests/ui/useless_conversion.rs:63:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:67:13 + --> tests/ui/useless_conversion.rs:69:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:72:17 + --> tests/ui/useless_conversion.rs:74:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:134:21 + --> tests/ui/useless_conversion.rs:136:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:135:21 + --> tests/ui/useless_conversion.rs:137:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:136:13 + --> tests/ui/useless_conversion.rs:138:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:137:13 + --> tests/ui/useless_conversion.rs:139:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:138:13 + --> tests/ui/useless_conversion.rs:140:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> tests/ui/useless_conversion.rs:139:13 + --> tests/ui/useless_conversion.rs:141:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:140:21 + --> tests/ui/useless_conversion.rs:142:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:145:13 + --> tests/ui/useless_conversion.rs:147:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:151:23 + --> tests/ui/useless_conversion.rs:153:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:153:13 + --> tests/ui/useless_conversion.rs:155:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> tests/ui/useless_conversion.rs:155:13 + --> tests/ui/useless_conversion.rs:157:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:187:7 + --> tests/ui/useless_conversion.rs:189:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:177:13 + --> tests/ui/useless_conversion.rs:179:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:188:7 + --> tests/ui/useless_conversion.rs:190:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:178:18 + --> tests/ui/useless_conversion.rs:180:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:189:7 + --> tests/ui/useless_conversion.rs:191:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:181:12 + --> tests/ui/useless_conversion.rs:183:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:192:7 + --> tests/ui/useless_conversion.rs:194:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:177:13 + --> tests/ui/useless_conversion.rs:179:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:193:7 + --> tests/ui/useless_conversion.rs:195:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:177:13 + --> tests/ui/useless_conversion.rs:179:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:239:24 + --> tests/ui/useless_conversion.rs:241:24 | LL | foo2::([1, 2, 3].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:218:12 + --> tests/ui/useless_conversion.rs:220:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:247:14 + --> tests/ui/useless_conversion.rs:249:14 | LL | foo3([1, 2, 3].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:227:12 + --> tests/ui/useless_conversion.rs:229:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:256:16 + --> tests/ui/useless_conversion.rs:258:16 | LL | S1.foo([1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:253:27 + --> tests/ui/useless_conversion.rs:255:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:275:44 + --> tests/ui/useless_conversion.rs:277:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); | ^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `v1` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:262:20 + --> tests/ui/useless_conversion.rs:264:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ -error: aborting due to 28 previous errors +error: useless conversion to the same type: `()` + --> tests/ui/useless_conversion.rs:304:58 + | +LL | let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); + | ^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `std::io::Error` + --> tests/ui/useless_conversion.rs:306:58 + | +LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); + | ^^^^^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `()` + --> tests/ui/useless_conversion.rs:308:58 + | +LL | let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); + | ^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `std::io::Error` + --> tests/ui/useless_conversion.rs:310:58 + | +LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); + | ^^^^^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `()` + --> tests/ui/useless_conversion.rs:314:31 + | +LL | let _: ControlFlow<()> = c.map_break(Into::into); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `()` + --> tests/ui/useless_conversion.rs:317:31 + | +LL | let _: ControlFlow<()> = c.map_continue(Into::into); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `u32` + --> tests/ui/useless_conversion.rs:331:41 + | +LL | let _: Vec = [1u32].into_iter().map(Into::into).collect(); + | ^^^^^^^^^^^^^^^^ help: consider removing + +error: useless conversion to the same type: `T` + --> tests/ui/useless_conversion.rs:342:18 + | +LL | x.into_iter().map(Into::into).collect() + | ^^^^^^^^^^^^^^^^ help: consider removing + +error: aborting due to 36 previous errors diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs index b41bcce3f7f7c..6f0d2760a860d 100644 --- a/tests/ui/zombie_processes.rs +++ b/tests/ui/zombie_processes.rs @@ -1,7 +1,7 @@ #![warn(clippy::zombie_processes)] -#![allow(clippy::if_same_then_else, clippy::ifs_same_cond)] +#![allow(clippy::if_same_then_else, clippy::ifs_same_cond, clippy::needless_return)] -use std::process::{Child, Command}; +use std::process::{Child, Command, ExitStatus}; fn main() { { @@ -12,7 +12,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes x.kill(); x.id(); } @@ -39,7 +39,7 @@ fn main() { } { let mut x = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes let v = &x; // (allow shared refs is fine because one cannot call `.wait()` through that) } @@ -64,14 +64,14 @@ fn main() { // It should assume that it might not exit and still lint { let mut x = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes if true { std::process::exit(0); } } { let mut x = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes if true { while false {} // Calling `exit()` after leaving a while loop should still be linted. @@ -97,7 +97,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes if true { return; } @@ -106,12 +106,32 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes if true { x.wait().unwrap(); } } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ zombie_processes + if true { + x.wait().unwrap(); + } else { + // this else block exists to test the other help message + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ zombie_processes + if true { + // this else block exists to test the other help message + } else { + x.wait().unwrap(); + } + } + { let mut x = Command::new("").spawn().unwrap(); if true { @@ -143,3 +163,8 @@ fn main() { fn process_child(c: Child) { todo!() } + +fn return_wait() -> ExitStatus { + let mut x = Command::new("").spawn().unwrap(); + return x.wait().unwrap(); +} diff --git a/tests/ui/zombie_processes.stderr b/tests/ui/zombie_processes.stderr index eec821a4c8f18..afc518c60db2a 100644 --- a/tests/ui/zombie_processes.stderr +++ b/tests/ui/zombie_processes.stderr @@ -4,7 +4,7 @@ error: spawned process is never `wait()`ed on LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider calling `.wait()` + = help: consider calling `.wait()` = note: not doing so might leave behind zombie processes = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning = note: `-D clippy::zombie-processes` implied by `-D warnings` @@ -16,7 +16,7 @@ error: spawned process is never `wait()`ed on LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider calling `.wait()` + = help: consider calling `.wait()` = note: not doing so might leave behind zombie processes = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning @@ -26,7 +26,7 @@ error: spawned process is never `wait()`ed on LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider calling `.wait()` + = help: consider calling `.wait()` = note: not doing so might leave behind zombie processes = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning @@ -36,29 +36,96 @@ error: spawned process is never `wait()`ed on LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider calling `.wait()` + = help: consider calling `.wait()` = note: not doing so might leave behind zombie processes = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning -error: spawned process is never `wait()`ed on +error: spawned process is not `wait()`ed on in all code paths --> tests/ui/zombie_processes.rs:99:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider calling `.wait()` +note: no `wait()` call exists on the code path to this early return + --> tests/ui/zombie_processes.rs:102:13 + | +LL | return; + | ^^^^^^ +note: `wait()` call exists, but it is unreachable due to the early return + --> tests/ui/zombie_processes.rs:104:9 + | +LL | x.wait().unwrap(); + | ^ + = help: consider calling `.wait()` in all code paths = note: not doing so might leave behind zombie processes = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning -error: spawned process is never `wait()`ed on +error: spawned process is not `wait()`ed on in all code paths --> tests/ui/zombie_processes.rs:108:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consider calling `.wait()` +note: this if expression has a `wait()` call, but it is missing an else block + --> tests/ui/zombie_processes.rs:110:9 + | +LL | / if true { +LL | | x.wait().unwrap(); +LL | | } + | |_________^ +note: `wait()` called here + --> tests/ui/zombie_processes.rs:111:13 + | +LL | x.wait().unwrap(); + | ^ + = help: consider calling `.wait()` in all code paths + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is not `wait()`ed on in all code paths + --> tests/ui/zombie_processes.rs:116:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `wait()` is not called in this if branch + --> tests/ui/zombie_processes.rs:120:10 + | +LL | } else { + | __________^ +LL | | // this else block exists to test the other help message +LL | | } + | |_________^ +note: `wait()` is called in the other branch + --> tests/ui/zombie_processes.rs:119:13 + | +LL | x.wait().unwrap(); + | ^ + = help: consider calling `.wait()` in all code paths + = note: not doing so might leave behind zombie processes + = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning + +error: spawned process is not `wait()`ed on in all code paths + --> tests/ui/zombie_processes.rs:126:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: `wait()` is not called in this if branch + --> tests/ui/zombie_processes.rs:128:9 + | +LL | / if true { +LL | | // this else block exists to test the other help message +LL | | } else { + | |_________^ +note: `wait()` is called in the other branch + --> tests/ui/zombie_processes.rs:131:13 + | +LL | x.wait().unwrap(); + | ^ + = help: consider calling `.wait()` in all code paths = note: not doing so might leave behind zombie processes = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 9a5365b2158b6..c2197b89c566e 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -232,13 +232,13 @@ const APPLICABILITIES_FILTER_DEFAULT = { MaybeIncorrect: true, HasPlaceholders: true, }; -const URL_PARAMS_CORRESPONDANCE = { +const URL_PARAMS_CORRESPONDENCE = { "groups_filter": "groups", "levels_filter": "levels", "applicabilities_filter": "applicabilities", "version_filter": "versions", }; -const VERSIONS_CORRESPONDANCE = { +const VERSIONS_CORRESPONDENCE = { "lte": "≤", "gte": "≥", "eq": "=", @@ -285,7 +285,7 @@ window.filters = { } function updateIfNeeded(filterName, obj2) { const obj1 = filters[filterName]; - const name = URL_PARAMS_CORRESPONDANCE[filterName]; + const name = URL_PARAMS_CORRESPONDENCE[filterName]; if (!compareObjects(obj1, obj2)) { urlParams.set( name, @@ -316,9 +316,9 @@ window.filters = { versions.push(`lte:${filters.version_filter["≤"]}`); } if (versions.length !== 0) { - urlParams.set(URL_PARAMS_CORRESPONDANCE["version_filter"], versions.join(",")); + urlParams.set(URL_PARAMS_CORRESPONDENCE["version_filter"], versions.join(",")); } else { - urlParams.delete(URL_PARAMS_CORRESPONDANCE["version_filter"]); + urlParams.delete(URL_PARAMS_CORRESPONDENCE["version_filter"]); } let params = urlParams.toString(); @@ -532,7 +532,7 @@ function parseURLFilters() { const urlParams = new URLSearchParams(window.location.search); for (const [key, value] of urlParams.entries()) { - for (const [corres_key, corres_value] of Object.entries(URL_PARAMS_CORRESPONDANCE)) { + for (const [corres_key, corres_value] of Object.entries(URL_PARAMS_CORRESPONDENCE)) { if (corres_value === key) { if (key !== "versions") { const settings = new Set(value.split(",")); @@ -545,7 +545,7 @@ function parseURLFilters() { for (const [kind, value] of settings) { const elem = document.querySelector( - `#version-filter input[data-value="${VERSIONS_CORRESPONDANCE[kind]}"]`); + `#version-filter input[data-value="${VERSIONS_CORRESPONDENCE[kind]}"]`); elem.value = value; updateVersionFilters(elem, true); } From 8a38bcc39083a2c73c2b7f27870d6bef85756f52 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Tue, 26 Nov 2024 06:09:29 -0500 Subject: [PATCH 013/189] Make "all fields are shorthand" requirement configurable Handle field attributes in suggestions Fix adjacent code Address review comments https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1861352124 Address all review comments but one This comment is not yet addressed: https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874544907 `initializer_suggestions` -> `lint_inconsistent_struct_field_initializers` --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 27 ++++ clippy.toml | 2 + clippy_config/src/conf.rs | 20 +++ clippy_dev/src/fmt.rs | 6 +- .../src/arbitrary_source_item_ordering.rs | 2 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/entry.rs | 4 +- clippy_lints/src/implied_bounds_in_impls.rs | 4 +- .../src/inconsistent_struct_constructor.rs | 127 +++++++++++++----- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/loops/infinite_loop.rs | 2 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 6 +- clippy_lints/src/methods/needless_collect.rs | 10 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/methods/unnecessary_fold.rs | 8 +- clippy_lints/src/needless_continue.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 2 +- .../src/operators/arithmetic_side_effects.rs | 2 +- clippy_lints/src/pathbuf_init_then_push.rs | 8 +- .../src/significant_drop_tightening.rs | 4 +- clippy_lints/src/swap.rs | 4 +- clippy_lints/src/types/mod.rs | 2 +- clippy_lints/src/unused_async.rs | 6 +- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 4 +- clippy_lints/src/write.rs | 2 +- clippy_lints/src/zombie_processes.rs | 2 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/mir/possible_borrower.rs | 2 +- lintcheck/src/output.rs | 2 +- tests/compile-test.rs | 2 +- .../clippy.toml | 1 + ...conf_inconsistent_struct_constructor.fixed | 79 +++++++++++ .../conf_inconsistent_struct_constructor.rs | 79 +++++++++++ ...onf_inconsistent_struct_constructor.stderr | 77 +++++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 3 + .../ui/inconsistent_struct_constructor.fixed | 6 +- .../ui/inconsistent_struct_constructor.stderr | 19 +-- 41 files changed, 450 insertions(+), 97 deletions(-) create mode 100644 tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml create mode 100644 tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed create mode 100644 tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs create mode 100644 tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index cc966972939a7..7f34b58938e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6250,6 +6250,7 @@ Released 2018-09-13 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold +[`lint-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inconsistent-struct-field-initializers [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold [`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else [`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 275d125096e95..f3a6d99afe35e 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -572,6 +572,33 @@ The maximum size of the `Err`-variant in a `Result` returned from a function * [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) +## `lint-inconsistent-struct-field-initializers` +Whether to suggest reordering constructor fields when initializers are present. + +Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the +suggested code would compile, it can change semantics if the initializer expressions have side effects. The +following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors: + +```rust +struct MyStruct { + vector: Vec, + length: usize +} +fn main() { + let vector = vec![1,2,3]; + MyStruct { length: vector.len(), vector}; +} +``` + +[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924 + +**Default Value:** `false` + +--- +**Affected lints:** +* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor) + + ## `literal-representation-threshold` The lower bound for linting decimal literals diff --git a/clippy.toml b/clippy.toml index a7b0cc56ea127..f4789c9d03035 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,5 +1,7 @@ avoid-breaking-exported-api = false +lint-inconsistent-struct-field-initializers = true + [[disallowed-methods]] path = "rustc_lint::context::LintContext::lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 41b56b45d9aef..de23e2e05d3b6 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -529,6 +529,26 @@ define_Conf! { /// The maximum size of the `Err`-variant in a `Result` returned from a function #[lints(result_large_err)] large_error_threshold: u64 = 128, + /// Whether to suggest reordering constructor fields when initializers are present. + /// + /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the + /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The + /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors: + /// + /// ```rust + /// struct MyStruct { + /// vector: Vec, + /// length: usize + /// } + /// fn main() { + /// let vector = vec![1,2,3]; + /// MyStruct { length: vector.len(), vector}; + /// } + /// ``` + /// + /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924 + #[lints(inconsistent_struct_constructor)] + lint_inconsistent_struct_field_initializers: bool = false, /// The lower bound for linting decimal literals #[lints(decimal_literal_representation)] literal_representation_threshold: u64 = 16384, diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index c667385928208..790dafa811f9e 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -179,8 +179,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> { #[expect(clippy::drain_collect)] fields.push(ClippyConf { name, - lints: lints.drain(..).collect(), attrs: &conf[attrs_start..attrs_end], + lints: lints.drain(..).collect(), field: conf[field_start..i].trim_end(), }); attrs_start = i; @@ -191,8 +191,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> { #[expect(clippy::drain_collect)] fields.push(ClippyConf { name, - lints: lints.drain(..).collect(), attrs: &conf[attrs_start..attrs_end], + lints: lints.drain(..).collect(), field: conf[field_start..i].trim_end(), }); attrs_start = i; @@ -220,8 +220,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> { } fields.push(ClippyConf { name, - lints, attrs: &conf[attrs_start..attrs_end], + lints, field: conf[field_start..].trim_end(), }); diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs index cf33e1444e47d..07d48344d80fe 100644 --- a/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -428,8 +428,8 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { // Makes a note of the current item for comparison with the next. cur_t = Some(CurItem { - order: module_level_order, item, + order: module_level_order, name: get_item_name(item), }); } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index fd86db21c1655..5478a80383a6e 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -798,8 +798,8 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ parser.into_offset_iter(), &doc, Fragments { - fragments: &fragments, doc: &doc, + fragments: &fragments, }, )) } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 70524e458c78b..2bec4f2f99e5b 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -678,12 +678,12 @@ fn find_insert_calls<'tcx>( map: contains_expr.map, key: contains_expr.key, ctxt: expr.span.ctxt(), - edits: Vec::new(), - is_map_used: false, allow_insert_closure: true, can_use_entry: true, in_tail_pos: true, is_single_insert: true, + is_map_used: false, + edits: Vec::new(), loops: Vec::new(), locals: HirIdSet::default(), }; diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 4427edb752e0e..ef272c305d34a 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -243,11 +243,11 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds && !predicates.is_empty() { Some(ImplTraitBound { + span: bound.span(), predicates, + trait_def_id, args: path.args.map_or([].as_slice(), |p| p.args), constraints: path.args.map_or([].as_slice(), |p| p.constraints), - trait_def_id, - span: bound.span(), }) } else { None diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 4fcd2abb76945..39ff3c13bcce9 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,19 +1,21 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fulfill_or_allowed; use clippy_utils::source::snippet; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::{self as hir, ExprKind, StructTailExpr}; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_middle::ty::TyCtxt; +use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::symbol::Symbol; -use std::fmt::{self, Write as _}; declare_clippy_lint! { /// ### What it does - /// Checks for struct constructors where all fields are shorthand and - /// the order of the field init shorthand in the constructor is inconsistent - /// with the order in the struct definition. + /// Checks for struct constructors where the order of the field + /// init in the constructor is inconsistent with the order in the + /// struct definition. /// /// ### Why is this bad? /// Since the order of fields in a constructor doesn't affect the @@ -59,16 +61,37 @@ declare_clippy_lint! { #[clippy::version = "1.52.0"] pub INCONSISTENT_STRUCT_CONSTRUCTOR, pedantic, - "the order of the field init shorthand is inconsistent with the order in the struct definition" + "the order of the field init is inconsistent with the order in the struct definition" } -declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]); +pub struct InconsistentStructConstructor { + lint_inconsistent_struct_field_initializers: bool, +} + +impl InconsistentStructConstructor { + pub fn new(conf: &'static Conf) -> Self { + Self { + lint_inconsistent_struct_field_initializers: conf.lint_inconsistent_struct_field_initializers, + } + } +} + +impl_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]); impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if let ExprKind::Struct(qpath, fields, base) = expr.kind - && fields.iter().all(|f| f.is_shorthand) - && !expr.span.from_expansion() + let ExprKind::Struct(_, fields, _) = expr.kind else { + return; + }; + let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand); + let applicability = if all_fields_are_shorthand { + Applicability::MachineApplicable + } else if self.lint_inconsistent_struct_field_initializers { + Applicability::MaybeIncorrect + } else { + return; + }; + if !expr.span.from_expansion() && let ty = cx.typeck_results().expr_ty(expr) && let Some(adt_def) = ty.ty_adt_def() && adt_def.is_struct() @@ -85,36 +108,24 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { return; } - let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect(); - ordered_fields.sort_unstable_by_key(|id| def_order_map[id]); - - let mut fields_snippet = String::new(); - let (last_ident, idents) = ordered_fields.split_last().unwrap(); - for ident in idents { - let _: fmt::Result = write!(fields_snippet, "{ident}, "); - } - fields_snippet.push_str(&last_ident.to_string()); - - let base_snippet = if let StructTailExpr::Base(base) = base { - format!(", ..{}", snippet(cx, base.span, "..")) - } else { - String::new() - }; - - let sugg = format!( - "{} {{ {fields_snippet}{base_snippet} }}", - snippet(cx, qpath.span(), ".."), - ); + let span = field_with_attrs_span(cx.tcx, fields.first().unwrap()) + .with_hi(field_with_attrs_span(cx.tcx, fields.last().unwrap()).hi()); if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) { - span_lint_and_sugg( + span_lint_and_then( cx, INCONSISTENT_STRUCT_CONSTRUCTOR, - expr.span, + span, "struct constructor field order is inconsistent with struct definition field order", - "try", - sugg, - Applicability::MachineApplicable, + |diag| { + let msg = if all_fields_are_shorthand { + "try" + } else { + "if the field evaluation order doesn't matter, try" + }; + let sugg = suggestion(cx, fields, &def_order_map); + diag.span_suggestion(span, msg, sugg, applicability); + }, ); } } @@ -135,3 +146,45 @@ fn is_consistent_order<'tcx>(fields: &'tcx [hir::ExprField<'tcx>], def_order_map true } + +fn suggestion<'tcx>( + cx: &LateContext<'_>, + fields: &'tcx [hir::ExprField<'tcx>], + def_order_map: &FxHashMap, +) -> String { + let ws = fields + .windows(2) + .map(|w| { + let w0_span = field_with_attrs_span(cx.tcx, &w[0]); + let w1_span = field_with_attrs_span(cx.tcx, &w[1]); + let span = w0_span.between(w1_span); + snippet(cx, span, " ") + }) + .collect::>(); + + let mut fields = fields.to_vec(); + fields.sort_unstable_by_key(|field| def_order_map[&field.ident.name]); + let field_snippets = fields + .iter() + .map(|field| snippet(cx, field_with_attrs_span(cx.tcx, field), "..")) + .collect::>(); + + assert_eq!(field_snippets.len(), ws.len() + 1); + + let mut sugg = String::new(); + for i in 0..field_snippets.len() { + sugg += &field_snippets[i]; + if i < ws.len() { + sugg += &ws[i]; + } + } + sugg +} + +fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span { + if let Some(attr) = tcx.hir().attrs(field.hir_id).first() { + field.span.with_lo(attr.span.lo()) + } else { + field.span + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 25713001f2177..54724dcb15fd1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -648,7 +648,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn)); store.register_late_pass(move |_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub::new(conf))); store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback)); - store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); + store.register_late_pass(move |_| { + Box::new(inconsistent_struct_constructor::InconsistentStructConstructor::new( + conf, + )) + }); store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(conf))); diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs index 9f543b79bac44..d863f6f9ab6d9 100644 --- a/clippy_lints/src/loops/infinite_loop.rs +++ b/clippy_lints/src/loops/infinite_loop.rs @@ -38,8 +38,8 @@ pub(super) fn check<'tcx>( cx, label, inner_labels: label.into_iter().collect(), - is_finite: false, loop_depth: 0, + is_finite: false, }; loop_visitor.visit_block(loop_block); diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index 312bcb55a9533..006addb987f5b 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -220,11 +220,11 @@ impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe { // `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span let mut vis = BodyVisitor { + macro_unsafe_blocks: Vec::new(), #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning expn_depth: if body.value.span.from_expansion() { 1 } else { 0 }, - macro_unsafe_blocks: Vec::new(), - lint: self, - cx + cx, + lint: self }; vis.visit_body(body); } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index ea4984f83adb2..2780c3f8af5cb 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -470,14 +470,14 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>( captured_ids: HirIdSet, ) -> Option> { let mut visitor = IterFunctionVisitor { - uses: Vec::new(), - target: id, - seen_other: false, - cx, - current_mutably_captured_ids: HirIdSet::default(), illegal_mutable_capture_ids: captured_ids, + current_mutably_captured_ids: HirIdSet::default(), + cx, + uses: Vec::new(), hir_id_uses_map: FxHashMap::default(), current_statement_hir_id: None, + seen_other: false, + target: id, }; visitor.visit_block(block); if visitor.seen_other { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index c6d4ef5911ee2..8a99974394c32 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -297,8 +297,8 @@ fn parse_iter_usage<'tcx>( { Some(IterUsage { kind: IterUsageKind::NextTuple, - span: e.span, unwrap_kind: None, + span: e.span, }) } else { None diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index b5d8972d7aad5..c27d1fb4903b3 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -124,30 +124,30 @@ pub(super) fn check( match lit.node { ast::LitKind::Bool(false) => { check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement { + method_name: "any", has_args: true, has_generic_return: false, - method_name: "any", }); }, ast::LitKind::Bool(true) => { check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement { + method_name: "all", has_args: true, has_generic_return: false, - method_name: "all", }); }, ast::LitKind::Int(Pu128(0), _) => { check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement { + method_name: "sum", has_args: false, has_generic_return: needs_turbofish(cx, expr), - method_name: "sum", }); }, ast::LitKind::Int(Pu128(1), _) => { check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement { + method_name: "product", has_args: false, has_generic_return: needs_turbofish(cx, expr), - method_name: "product", }); }, _ => (), diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index c48232f990582..a7cd29bb8e329 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -349,11 +349,11 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { for (i, stmt) in loop_block.stmts.iter().enumerate() { with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { let data = &LintData { - stmt_idx: i, if_expr, if_cond: cond, if_block: then_block, else_expr, + stmt_idx: i, loop_block, }; if needless_continue_in_else(else_expr, label) { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 2fee1c72a91b5..56c4157d6fe05 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -270,10 +270,10 @@ impl SimilarNamesNameVisitor<'_, '_, '_> { return; } self.0.names.push(ExistingName { - exemptions: get_exemptions(interned_name).unwrap_or(&[]), interned: ident.name, span: ident.span, len: count, + exemptions: get_exemptions(interned_name).unwrap_or(&[]), }); } diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 65ef56fd21127..0eca788c78746 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -47,6 +47,7 @@ impl ArithmeticSideEffects { Self { allowed_binary, allowed_unary, + const_span: None, disallowed_int_methods: [ sym::saturating_div, sym::wrapping_div, @@ -55,7 +56,6 @@ impl ArithmeticSideEffects { ] .into_iter() .collect(), - const_span: None, expr_span: None, } } diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index d2529d4d9f857..668f09bbfd58e 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -143,11 +143,11 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> { self.searcher = Some(PathbufPushSearcher { local_id: id, lhs_is_let: true, - name: name.name, let_ty_span: local.ty.map(|ty| ty.span), - err_span: local.span, init_val: *init_expr, arg: None, + name: name.name, + err_span: local.span, }); } } @@ -165,10 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> { local_id: id, lhs_is_let: false, let_ty_span: None, - name: name.ident.name, - err_span: expr.span, init_val: *right, arg: None, + name: name.ident.name, + err_span: expr.span, }); } } diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index c690696aefc19..597bfddecbc5f 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -282,9 +282,9 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { } { let mut apa = AuxParamsAttr { - first_bind_ident: ident, first_block_hir_id: self.ap.curr_block_hir_id, first_block_span: self.ap.curr_block_span, + first_bind_ident: ident, first_method_span: { let expr_or_init = expr_or_init(self.cx, expr); if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind { @@ -395,8 +395,8 @@ impl Default for AuxParamsAttr { counter: 0, has_expensive_expr_after_last_attr: false, first_block_hir_id: HirId::INVALID, - first_bind_ident: Ident::empty(), first_block_span: DUMMY_SP, + first_bind_ident: Ident::empty(), first_method_span: DUMMY_SP, first_stmt_span: DUMMY_SP, last_bind_ident: Ident::empty(), diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 78f0b7d121c26..ff11680051232 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -384,9 +384,9 @@ impl<'tcx> IndexBinding<'_, 'tcx> { fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool { let mut v = IndexBindingVisitor { - found_used: false, - suggest_span: self.suggest_span, idx: idx_ident, + suggest_span: self.suggest_span, + found_used: false, }; for stmt in self.block.stmts { diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 363aea8be72e9..43cce625c6411 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -388,8 +388,8 @@ impl<'tcx> LateLintPass<'tcx> for Types { self.check_fn_decl(cx, decl, CheckTyContext { is_in_trait_impl, - is_exported, in_body: matches!(fn_kind, FnKind::Closure), + is_exported, ..CheckTyContext::default() }); } diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index c899b1868a6cf..d00bd7f2b3dbf 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -120,8 +120,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { let mut visitor = AsyncFnVisitor { cx, found_await: false, - async_depth: 0, await_in_async_block: None, + async_depth: 0, }; walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id); if !visitor.found_await { @@ -129,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { // The actual linting happens in `check_crate_post`, once we've found all // uses of local async functions that do require asyncness to pass typeck self.unused_async_fns.push(UnusedAsyncFn { - await_in_async_block: visitor.await_in_async_block, - fn_span: span, def_id, + fn_span: span, + await_in_async_block: visitor.await_in_async_block, }); } } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 89bb429e26562..eaa119b045f1c 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -245,9 +245,9 @@ impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> { let prev_len = self.unwrappables.len(); for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) { let mut delegate = MutationVisitor { - tcx: self.cx.tcx, is_mutated: false, local_id: unwrap_info.local_id, + tcx: self.cx.tcx, }; let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate); @@ -397,8 +397,8 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap { } let mut v = UnwrappableVariablesVisitor { - cx, unwrappables: Vec::new(), + cx, }; walk_fn(&mut v, kind, decl, body.id(), fn_id); diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index cbc6885ae5de3..d87d554eb0749 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -166,8 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { local_id: id, init, lhs_is_let: true, - name: name.name, let_ty_span: local.ty.map(|ty| ty.span), + name: name.name, err_span: local.span, found: 0, last_push_expr: init_expr.hir_id, @@ -206,8 +206,8 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { && name.ident.as_str() == "push" { self.searcher = Some(VecPushSearcher { - found: searcher.found + 1, err_span: searcher.err_span.to(stmt.span), + found: searcher.found + 1, last_push_expr: expr.hir_id, ..searcher }); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index a42ddcdae353e..31ae002e47d98 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -248,8 +248,8 @@ impl Write { pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self { Self { format_args, - allow_print_in_tests: conf.allow_print_in_tests, in_debug_impl: false, + allow_print_in_tests: conf.allow_print_in_tests, } } } diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index a702e0785a960..4df34891a2b1a 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -300,8 +300,8 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus }; let mut vis = ExitPointFinder { - cx, state: ExitPointState::WalkUpTo(spawn_expr.hir_id), + cx, }; if let Break(ExitCallFound) = vis.visit_block(block) { // Visitor found an unconditional `exit()` call, so don't lint. diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 4e12577b6df6b..60be7e4a4d395 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -196,8 +196,8 @@ impl<'hir> IfOrIfLet<'hir> { if let ExprKind::DropTemps(new_cond) = cond.kind { return Some(Self { cond: new_cond, - r#else, then, + r#else, }); } if let ExprKind::Let(..) = cond.kind { diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index ed52c481de124..dce24d26f2ae6 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -788,8 +788,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { Self { cx, maybe_typeck_results: cx.maybe_typeck_results(), - path_check: PathCheck::default(), s: FxHasher::default(), + path_check: PathCheck::default(), } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index d11f1a6c12f54..f4d75e8b2283b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1232,9 +1232,9 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' let mut v = V { cx, - allow_closure: true, loops: Vec::new(), locals: HirIdSet::default(), + allow_closure: true, captures: HirIdMap::default(), }; v.visit_expr(expr); diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 17e6558a41c45..cf73bae2583b1 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -32,8 +32,8 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> { ) -> Self { Self { possible_borrower: TransitiveRelation::default(), - cx, body, + cx, possible_origin, } } diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs index e38036315c2ce..dcc1ec339ef90 100644 --- a/lintcheck/src/output.rs +++ b/lintcheck/src/output.rs @@ -94,8 +94,8 @@ impl ClippyWarning { Some(Self { name, diag, - url, krate: krate.to_string(), + url, }) } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index b8e0413e97bc1..e2e4d92df79f9 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -574,12 +574,12 @@ impl LintMetadata { id_location: None, group: "deprecated", level: "none", - version, docs: format!( "### What it does\n\n\ Nothing. This lint has been deprecated\n\n\ ### Deprecation reason\n\n{reason}.\n", ), + version, applicability: Applicability::Unspecified, } } diff --git a/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml b/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml new file mode 100644 index 0000000000000..f43c9d97e825d --- /dev/null +++ b/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml @@ -0,0 +1 @@ +lint-inconsistent-struct-field-initializers = true diff --git a/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed b/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed new file mode 100644 index 0000000000000..8092e40ff9f19 --- /dev/null +++ b/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed @@ -0,0 +1,79 @@ +#![warn(clippy::inconsistent_struct_constructor)] +#![allow(clippy::redundant_field_names)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::no_effect)] + +#[derive(Default)] +struct Foo { + x: i32, + y: i32, + z: i32, +} + +fn main() { + let x = 1; + let y = 1; + let z = 1; + + Foo { x, y, z: z }; + + Foo { + x, + z: z, + ..Default::default() + }; +} + +// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645 +mod field_attributes { + struct HirId; + struct BodyVisitor { + macro_unsafe_blocks: Vec, + expn_depth: u32, + } + fn check_body(condition: bool) { + BodyVisitor { + macro_unsafe_blocks: Vec::new(), + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning + expn_depth: if condition { 1 } else { 0 }, + }; + } +} + +// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800 +mod cfgs_between_fields { + #[allow(clippy::non_minimal_cfg)] + fn cfg_all() { + struct S { + a: i32, + b: i32, + #[cfg(all())] + c: i32, + d: i32, + } + let s = S { + a: 3, + b: 2, + #[cfg(all())] + c: 1, + d: 0, + }; + } + + fn cfg_any() { + struct S { + a: i32, + b: i32, + #[cfg(any())] + c: i32, + d: i32, + } + let s = S { + a: 3, + #[cfg(any())] + c: 1, + b: 2, + d: 0, + }; + } +} diff --git a/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs b/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs new file mode 100644 index 0000000000000..cd1aff9665282 --- /dev/null +++ b/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs @@ -0,0 +1,79 @@ +#![warn(clippy::inconsistent_struct_constructor)] +#![allow(clippy::redundant_field_names)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::no_effect)] + +#[derive(Default)] +struct Foo { + x: i32, + y: i32, + z: i32, +} + +fn main() { + let x = 1; + let y = 1; + let z = 1; + + Foo { y, x, z: z }; + + Foo { + z: z, + x, + ..Default::default() + }; +} + +// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645 +mod field_attributes { + struct HirId; + struct BodyVisitor { + macro_unsafe_blocks: Vec, + expn_depth: u32, + } + fn check_body(condition: bool) { + BodyVisitor { + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning + expn_depth: if condition { 1 } else { 0 }, + macro_unsafe_blocks: Vec::new(), + }; + } +} + +// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800 +mod cfgs_between_fields { + #[allow(clippy::non_minimal_cfg)] + fn cfg_all() { + struct S { + a: i32, + b: i32, + #[cfg(all())] + c: i32, + d: i32, + } + let s = S { + d: 0, + #[cfg(all())] + c: 1, + b: 2, + a: 3, + }; + } + + fn cfg_any() { + struct S { + a: i32, + b: i32, + #[cfg(any())] + c: i32, + d: i32, + } + let s = S { + d: 0, + #[cfg(any())] + c: 1, + b: 2, + a: 3, + }; + } +} diff --git a/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr b/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr new file mode 100644 index 0000000000000..d2533960b84c1 --- /dev/null +++ b/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr @@ -0,0 +1,77 @@ +error: struct constructor field order is inconsistent with struct definition field order + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:18:11 + | +LL | Foo { y, x, z: z }; + | ^^^^^^^^^^ help: if the field evaluation order doesn't matter, try: `x, y, z: z` + | + = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]` + +error: struct constructor field order is inconsistent with struct definition field order + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:21:9 + | +LL | / z: z, +LL | | x, + | |_________^ + | +help: if the field evaluation order doesn't matter, try + | +LL ~ x, +LL ~ z: z, + | + +error: struct constructor field order is inconsistent with struct definition field order + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:36:13 + | +LL | / #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning +LL | | expn_depth: if condition { 1 } else { 0 }, +LL | | macro_unsafe_blocks: Vec::new(), + | |___________________________________________^ + | +help: if the field evaluation order doesn't matter, try + | +LL ~ macro_unsafe_blocks: Vec::new(), +LL + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning +LL ~ expn_depth: if condition { 1 } else { 0 }, + | + +error: struct constructor field order is inconsistent with struct definition field order + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:55:13 + | +LL | / d: 0, +LL | | #[cfg(all())] +LL | | c: 1, +LL | | b: 2, +LL | | a: 3, + | |________________^ + | +help: if the field evaluation order doesn't matter, try + | +LL ~ a: 3, +LL + b: 2, +LL + #[cfg(all())] +LL + c: 1, +LL ~ d: 0, + | + +error: struct constructor field order is inconsistent with struct definition field order + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:72:13 + | +LL | / d: 0, +LL | | #[cfg(any())] +LL | | c: 1, +LL | | b: 2, +LL | | a: 3, + | |________________^ + | +help: if the field evaluation order doesn't matter, try + | +LL ~ a: 3, +LL + #[cfg(any())] +LL + c: 1, +LL + b: 2, +LL ~ d: 0, + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6fa583fc0417a..c13dd76a821ef 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -45,6 +45,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect future-size-threshold ignore-interior-mutability large-error-threshold + lint-inconsistent-struct-field-initializers literal-representation-threshold matches-for-let-else max-fn-params-bools @@ -132,6 +133,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect future-size-threshold ignore-interior-mutability large-error-threshold + lint-inconsistent-struct-field-initializers literal-representation-threshold matches-for-let-else max-fn-params-bools @@ -219,6 +221,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni future-size-threshold ignore-interior-mutability large-error-threshold + lint-inconsistent-struct-field-initializers literal-representation-threshold matches-for-let-else max-fn-params-bools diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 4c324587c96fa..67bd3e4d2797e 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -60,7 +60,11 @@ mod with_base { let z = 1; // Should lint. - Foo { x, z, ..Default::default() }; + Foo { + x, + z, + ..Default::default() + }; // Should NOT lint because the order is consistent with the definition. Foo { diff --git a/tests/ui/inconsistent_struct_constructor.stderr b/tests/ui/inconsistent_struct_constructor.stderr index 97bb7c789a720..c145eb2a239e7 100644 --- a/tests/ui/inconsistent_struct_constructor.stderr +++ b/tests/ui/inconsistent_struct_constructor.stderr @@ -1,21 +1,24 @@ error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui/inconsistent_struct_constructor.rs:36:9 + --> tests/ui/inconsistent_struct_constructor.rs:36:15 | LL | Foo { y, x, z }; - | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` + | ^^^^^^^ help: try: `x, y, z` | = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]` error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui/inconsistent_struct_constructor.rs:63:9 + --> tests/ui/inconsistent_struct_constructor.rs:64:13 | -LL | / Foo { -LL | | z, +LL | / z, LL | | x, -LL | | ..Default::default() -LL | | }; - | |_________^ help: try: `Foo { x, z, ..Default::default() }` + | |_____________^ + | +help: try + | +LL ~ x, +LL ~ z, + | error: aborting due to 2 previous errors From 09022bbd4515ba12edb4188dac221b1b068ee981 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Sat, 28 Dec 2024 22:41:29 +0900 Subject: [PATCH 014/189] fix arguments of ExprKind::MethodCall --- book/src/development/method_checking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/development/method_checking.md b/book/src/development/method_checking.md index 9c5d4b516db2c..b3126024b990d 100644 --- a/book/src/development/method_checking.md +++ b/book/src/development/method_checking.md @@ -21,7 +21,7 @@ use clippy_utils::is_trait_method; impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // Check our expr is calling a method with pattern matching - if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind + if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind // Check if the name of this method is `our_fancy_method` && path.ident.name.as_str() == "our_fancy_method" // We can check the type of the self argument whenever necessary. From e582fcd75dda451c68c266d91d538f010f4a9b9f Mon Sep 17 00:00:00 2001 From: lengyijun Date: Wed, 20 Sep 2023 21:05:36 +0800 Subject: [PATCH 015/189] [`needless_continue`]: lint if the last stmt in for/while/loop is `continue`, recursively fixes: #4077 --- .../src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/needless_continue.rs | 122 ++++++++++++++---- clippy_lints/src/redundant_else.rs | 1 - .../src/transmute/transmute_undefined_repr.rs | 4 - tests/missing-test-files.rs | 2 +- tests/ui/needless_continue.rs | 39 ++++++ tests/ui/needless_continue.stderr | 38 +++++- 7 files changed, 172 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index d19064fd57e3e..a52851c9a1ab3 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -494,7 +494,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { match node { Node::Stmt(_) => return true, - Node::Block(..) => continue, + Node::Block(..) => {}, Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index a7cd29bb8e329..dd75e0f4e4bf2 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; -use rustc_ast::ast; +use rustc_ast::{Block, Label, ast}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -11,6 +11,7 @@ declare_clippy_lint! { /// that contain a `continue` statement in either their main blocks or their /// `else`-blocks, when omitting the `else`-block possibly with some /// rearrangement of code can make the code easier to understand. + /// The lint also checks if the last statement in the loop is a `continue` /// /// ### Why is this bad? /// Having explicit `else` blocks for `if` statements @@ -75,6 +76,45 @@ declare_clippy_lint! { /// # break; /// } /// ``` + /// + /// ```rust + /// fn foo() -> std::io::ErrorKind { std::io::ErrorKind::NotFound } + /// for _ in 0..10 { + /// match foo() { + /// std::io::ErrorKind::NotFound => { + /// eprintln!("not found"); + /// continue + /// } + /// std::io::ErrorKind::TimedOut => { + /// eprintln!("timeout"); + /// continue + /// } + /// _ => { + /// eprintln!("other error"); + /// continue + /// } + /// } + /// } + /// ``` + /// Could be rewritten as + /// + /// + /// ```rust + /// fn foo() -> std::io::ErrorKind { std::io::ErrorKind::NotFound } + /// for _ in 0..10 { + /// match foo() { + /// std::io::ErrorKind::NotFound => { + /// eprintln!("not found"); + /// } + /// std::io::ErrorKind::TimedOut => { + /// eprintln!("timeout"); + /// } + /// _ => { + /// eprintln!("other error"); + /// } + /// } + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_CONTINUE, pedantic, @@ -144,7 +184,7 @@ impl EarlyLintPass for NeedlessContinue { /// /// - The expression is a `continue` node. /// - The expression node is a block with the first statement being a `continue`. -fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool { +fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&Label>) -> bool { match else_expr.kind { ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label), ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()), @@ -152,7 +192,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) } } -fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool { +fn is_first_block_stmt_continue(block: &Block, label: Option<&Label>) -> bool { block.stmts.first().is_some_and(|stmt| match stmt.kind { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { if let ast::ExprKind::Continue(ref l) = e.kind { @@ -166,7 +206,7 @@ fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) } /// If the `continue` has a label, check it matches the label of the loop. -fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::Label>) -> bool { +fn compare_labels(loop_label: Option<&Label>, continue_label: Option<&Label>) -> bool { match (loop_label, continue_label) { // `loop { continue; }` or `'a loop { continue; }` (_, None) => true, @@ -181,7 +221,7 @@ fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast:: /// the AST object representing the loop block of `expr`. fn with_loop_block(expr: &ast::Expr, mut func: F) where - F: FnMut(&ast::Block, Option<&ast::Label>), + F: FnMut(&Block, Option<&Label>), { if let ast::ExprKind::While(_, loop_block, label) | ast::ExprKind::ForLoop { @@ -205,7 +245,7 @@ where /// - The `else` expression. fn with_if_expr(stmt: &ast::Stmt, mut func: F) where - F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr), + F: FnMut(&ast::Expr, &ast::Expr, &Block, &ast::Expr), { match stmt.kind { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { @@ -231,14 +271,14 @@ struct LintData<'a> { /// The condition expression for the above `if`. if_cond: &'a ast::Expr, /// The `then` block of the `if` statement. - if_block: &'a ast::Block, + if_block: &'a Block, /// The `else` block of the `if` statement. /// Note that we only work with `if` exprs that have an `else` branch. else_expr: &'a ast::Expr, /// The 0-based index of the `if` statement in the containing loop block. stmt_idx: usize, /// The statements of the loop block. - loop_block: &'a ast::Block, + loop_block: &'a Block, } const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant"; @@ -329,23 +369,61 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin ) } -fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { - if let ast::ExprKind::Loop(loop_block, loop_label, ..) = &expr.kind - && let Some(last_stmt) = loop_block.stmts.last() +fn check_last_stmt_in_expr(inner_expr: &ast::Expr, func: &F) +where + F: Fn(Option<&Label>, Span), +{ + match &inner_expr.kind { + ast::ExprKind::Continue(continue_label) => { + func(continue_label.as_ref(), inner_expr.span); + }, + ast::ExprKind::If(_, then_block, else_block) => { + check_last_stmt_in_block(then_block, func); + if let Some(else_block) = else_block { + check_last_stmt_in_expr(else_block, func); + } + }, + ast::ExprKind::Match(_, arms, _) => { + for arm in arms { + if let Some(expr) = &arm.body { + check_last_stmt_in_expr(expr, func); + } + } + }, + ast::ExprKind::Block(b, _) => { + check_last_stmt_in_block(b, func); + }, + _ => {}, + } +} + +fn check_last_stmt_in_block(b: &Block, func: &F) +where + F: Fn(Option<&Label>, Span), +{ + if let Some(last_stmt) = b.stmts.last() && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind - && let ast::ExprKind::Continue(continue_label) = inner_expr.kind - && compare_labels(loop_label.as_ref(), continue_label.as_ref()) { - span_lint_and_help( - cx, - NEEDLESS_CONTINUE, - last_stmt.span, - MSG_REDUNDANT_CONTINUE_EXPRESSION, - None, - DROP_CONTINUE_EXPRESSION_MSG, - ); + check_last_stmt_in_expr(inner_expr, func); } +} + +fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { with_loop_block(expr, |loop_block, label| { + let p = |continue_label: Option<&Label>, span: Span| { + if compare_labels(label, continue_label) { + span_lint_and_help( + cx, + NEEDLESS_CONTINUE, + span, + MSG_REDUNDANT_CONTINUE_EXPRESSION, + None, + DROP_CONTINUE_EXPRESSION_MSG, + ); + } + }; + check_last_stmt_in_block(loop_block, &p); + for (i, stmt) in loop_block.stmts.iter().enumerate() { with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { let data = &LintData { @@ -400,7 +478,7 @@ fn erode_from_back(s: &str) -> String { if ret.is_empty() { s.to_string() } else { ret } } -fn span_of_first_expr_in_block(block: &ast::Block) -> Option { +fn span_of_first_expr_in_block(block: &Block) -> Option { block.stmts.first().map(|stmt| stmt.span) } diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 6a1d40334e755..a27f9b6311430 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -69,7 +69,6 @@ impl EarlyLintPass for RedundantElse { ExprKind::If(_, next_then, Some(next_els)) => { then = next_then; els = next_els; - continue; }, // else if without else ExprKind::If(..) => return, diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 48d65eb15d9a7..26323af312288 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -30,17 +30,14 @@ pub(super) fn check<'tcx>( | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) => { from_ty = from_sub_ty; to_ty = to_sub_ty; - continue; }, (ReducedTy::OrderedFields(Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => { from_ty = from_sub_ty; to_ty = to_sub_ty; - continue; }, (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) if reduced_tys.from_fat_ptr => { from_ty = from_sub_ty; to_ty = to_sub_ty; - continue; }, // ptr <-> ptr @@ -50,7 +47,6 @@ pub(super) fn check<'tcx>( { from_ty = from_sub_ty; to_ty = to_sub_ty; - continue; }, // fat ptr <-> (*size, *size) diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index a8225d037e828..64eba5e0888a4 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -59,7 +59,7 @@ fn explore_directory(dir: &Path) -> Vec { missing_files.push(path.to_str().unwrap().to_string()); } }, - _ => continue, + _ => {}, }; } } diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index b6d8a8f61aeb0..bc7233f3ba506 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -87,6 +87,14 @@ fn simple_loop4() { } } +fn simple_loop5() { + loop { + println!("bleh"); + { continue } + //~^ ERROR: this `continue` expression is redundant + } +} + mod issue_2329 { fn condition() -> bool { unimplemented!() @@ -168,3 +176,34 @@ fn issue_13641() { } } } + +mod issue_4077 { + fn main() { + 'outer: loop { + 'inner: loop { + do_something(); + if some_expr() { + println!("bar-7"); + continue 'outer; + } else if !some_expr() { + println!("bar-8"); + continue 'inner; + } else { + println!("bar-9"); + continue 'inner; + } + } + } + } + + // The contents of these functions are irrelevant, the purpose of this file is + // shown in main. + + fn do_something() { + std::process::exit(0); + } + + fn some_expr() -> bool { + true + } +} diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index 0741ba6924870..4ab443108b0fa 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -63,7 +63,7 @@ error: this `continue` expression is redundant --> tests/ui/needless_continue.rs:60:9 | LL | continue; - | ^^^^^^^^^ + | ^^^^^^^^ | = help: consider dropping the `continue` expression @@ -71,7 +71,7 @@ error: this `continue` expression is redundant --> tests/ui/needless_continue.rs:68:9 | LL | continue; - | ^^^^^^^^^ + | ^^^^^^^^ | = help: consider dropping the `continue` expression @@ -91,8 +91,16 @@ LL | continue | = help: consider dropping the `continue` expression +error: this `continue` expression is redundant + --> tests/ui/needless_continue.rs:93:11 + | +LL | { continue } + | ^^^^^^^^ + | + = help: consider dropping the `continue` expression + error: this `else` block is redundant - --> tests/ui/needless_continue.rs:136:24 + --> tests/ui/needless_continue.rs:144:24 | LL | } else { | ________________________^ @@ -117,7 +125,7 @@ LL | | } } error: there is no need for an explicit `else` block for this `if` expression - --> tests/ui/needless_continue.rs:143:17 + --> tests/ui/needless_continue.rs:151:17 | LL | / if condition() { LL | | @@ -137,12 +145,28 @@ LL | | } } error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:166:13 + --> tests/ui/needless_continue.rs:174:13 | LL | continue 'b; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ + | + = help: consider dropping the `continue` expression + +error: this `continue` expression is redundant + --> tests/ui/needless_continue.rs:190:21 + | +LL | continue 'inner; + | ^^^^^^^^^^^^^^^ + | + = help: consider dropping the `continue` expression + +error: this `continue` expression is redundant + --> tests/ui/needless_continue.rs:193:21 + | +LL | continue 'inner; + | ^^^^^^^^^^^^^^^ | = help: consider dropping the `continue` expression -error: aborting due to 9 previous errors +error: aborting due to 12 previous errors From d7cc6c45c8f67f012b5111559bf321444e7c8722 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Wed, 25 Dec 2024 19:59:18 +0100 Subject: [PATCH 016/189] borrow_interior_mutable_const ICE into FN Convert the ICE reported in #12979 into a false negative. We prefer a false negative to a ICE (because the ICE could still affect the user even when not activating the lint). --- clippy_lints/src/non_copy_const.rs | 11 ++++---- .../borrow_interior_mutable_const/others.rs | 11 ++++++++ .../others.stderr | 28 +++++++++---------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index ebd301d5156a6..8409d179b0f58 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -189,6 +189,8 @@ impl<'tcx> NonCopyConst<'tcx> { } fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { + // No branch that we check (yet) should continue if val isn't a ValTree::Branch + let ty::ValTree::Branch(val) = val else { return false }; match *ty.kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. @@ -197,12 +199,13 @@ impl<'tcx> NonCopyConst<'tcx> { // contained value. ty::Adt(def, ..) if def.is_union() => false, ty::Array(ty, _) => val - .unwrap_branch() .iter() .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().to_u32()); + let Some((&ty::ValTree::Leaf(variant_index), fields)) = val.split_first() else { + return false; + }; + let variant_index = VariantIdx::from_u32(variant_index.to_u32()); fields .iter() .copied() @@ -215,12 +218,10 @@ impl<'tcx> NonCopyConst<'tcx> { .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty)) }, ty::Adt(def, args) => val - .unwrap_branch() .iter() .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Tuple(tys) => val - .unwrap_branch() .iter() .zip(tys) .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs index de220505c3e08..a49d53fbbd380 100644 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -47,6 +47,17 @@ impl std::ops::Deref for StaticRef { } } +// ICE regression test +mod issue12979 { + use std::cell::UnsafeCell; + + const ATOMIC_TUPLE: (Vec>, ()) = (Vec::new(), ()); + + fn main() { + let _x = &ATOMIC_TUPLE.0; + } +} + // use a tuple to make sure referencing a field behind a pointer isn't linted. const CELL_REF: StaticRef<(UnsafeCell,)> = unsafe { StaticRef::new(std::ptr::null()) }; diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 9a9028c864986..4cefcc28008d7 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:54:5 + --> tests/ui/borrow_interior_mutable_const/others.rs:65:5 | LL | ATOMIC.store(1, Ordering::SeqCst); | ^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:55:16 + --> tests/ui/borrow_interior_mutable_const/others.rs:66:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); | ^^^^^^ @@ -20,7 +20,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:58:22 + --> tests/ui/borrow_interior_mutable_const/others.rs:69:22 | LL | let _once_ref = &ONCE_INIT; | ^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _once_ref = &ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:59:25 + --> tests/ui/borrow_interior_mutable_const/others.rs:70:25 | LL | let _once_ref_2 = &&ONCE_INIT; | ^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:60:27 + --> tests/ui/borrow_interior_mutable_const/others.rs:71:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:61:26 + --> tests/ui/borrow_interior_mutable_const/others.rs:72:26 | LL | let _once_mut = &mut ONCE_INIT; | ^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _once_mut = &mut ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:72:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:83:14 | LL | let _ = &ATOMIC_TUPLE; | ^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _ = &ATOMIC_TUPLE; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:73:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:84:14 | LL | let _ = &ATOMIC_TUPLE.0; | ^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _ = &ATOMIC_TUPLE.0; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:74:19 + --> tests/ui/borrow_interior_mutable_const/others.rs:85:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; | ^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:75:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:86:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:76:13 + --> tests/ui/borrow_interior_mutable_const/others.rs:87:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); | ^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:81:13 + --> tests/ui/borrow_interior_mutable_const/others.rs:92:13 | LL | let _ = ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:86:5 + --> tests/ui/borrow_interior_mutable_const/others.rs:97:5 | LL | CELL.set(2); | ^^^^ @@ -108,7 +108,7 @@ LL | CELL.set(2); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:87:16 + --> tests/ui/borrow_interior_mutable_const/others.rs:98:16 | LL | assert_eq!(CELL.get(), 6); | ^^^^ From eef47fc0b74d4e3bae7548711a42328e93368cf4 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 27 Dec 2024 11:23:32 +0100 Subject: [PATCH 017/189] Do not remove required parentheses in `borrow_as_ptr` suggestion Also, simplify boolean expression, and ensure that proper applicability is used. --- clippy_lints/src/casts/borrow_as_ptr.rs | 29 ++++++++++++++----------- clippy_lints/src/casts/mod.rs | 7 ++---- tests/ui/borrow_as_ptr.fixed | 8 +++++++ tests/ui/borrow_as_ptr.rs | 8 +++++++ tests/ui/borrow_as_ptr.stderr | 14 +++++++++++- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index 67aa33ca06c31..6057144bc6a4b 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::{is_lint_allowed, msrvs, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; +use rustc_span::BytePos; use super::BORROW_AS_PTR; @@ -32,12 +34,21 @@ pub(super) fn check<'tcx>( return false; } - let suggestion = if msrv.meets(msrvs::RAW_REF_OP) { + let (suggestion, span) = if msrv.meets(msrvs::RAW_REF_OP) { let operator_kind = match mutability { Mutability::Not => "const", Mutability::Mut => "mut", }; - format!("&raw {operator_kind} {snip}") + // Make sure that the span to be replaced doesn't include parentheses, that could break the + // suggestion. + let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) { + expr.span + .with_lo(expr.span.lo() + BytePos(1)) + .with_hi(expr.span.hi() - BytePos(1)) + } else { + expr.span + }; + (format!("&raw {operator_kind} {snip}"), span) } else { let Some(std_or_core) = std_or_core(cx) else { return false; @@ -46,18 +57,10 @@ pub(super) fn check<'tcx>( Mutability::Not => "addr_of", Mutability::Mut => "addr_of_mut", }; - format!("{std_or_core}::ptr::{macro_name}!({snip})") + (format!("{std_or_core}::ptr::{macro_name}!({snip})"), expr.span) }; - span_lint_and_sugg( - cx, - BORROW_AS_PTR, - expr.span, - "borrow as raw pointer", - "try", - suggestion, - Applicability::MachineApplicable, - ); + span_lint_and_sugg(cx, BORROW_AS_PTR, span, "borrow as raw pointer", "try", suggestion, app); return true; } false diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index c64c0e15144de..d90cf124fe42a 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -836,11 +836,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { as_underscore::check(cx, expr, cast_to_hir); as_pointer_underscore::check(cx, cast_to, cast_to_hir); - let was_borrow_as_ptr_emitted = if self.msrv.meets(msrvs::BORROW_AS_PTR) { - borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv) - } else { - false - }; + let was_borrow_as_ptr_emitted = self.msrv.meets(msrvs::BORROW_AS_PTR) + && borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv); if self.msrv.meets(msrvs::PTR_FROM_REF) && !was_borrow_as_ptr_emitted { ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } diff --git a/tests/ui/borrow_as_ptr.fixed b/tests/ui/borrow_as_ptr.fixed index 289a5ef38b8dd..5365f3dd443c6 100644 --- a/tests/ui/borrow_as_ptr.fixed +++ b/tests/ui/borrow_as_ptr.fixed @@ -16,4 +16,12 @@ fn main() { let mut val_mut = 1; let _p_mut = std::ptr::addr_of_mut!(val_mut); + + let mut x: [i32; 2] = [42, 43]; + let _raw = std::ptr::addr_of_mut!(x[1]).wrapping_offset(-1); +} + +fn issue_13882() { + let mut x: [i32; 2] = [42, 43]; + let _raw = (&raw mut x[1]).wrapping_offset(-1); } diff --git a/tests/ui/borrow_as_ptr.rs b/tests/ui/borrow_as_ptr.rs index b5328cb22dcdb..261894f1341c4 100644 --- a/tests/ui/borrow_as_ptr.rs +++ b/tests/ui/borrow_as_ptr.rs @@ -16,4 +16,12 @@ fn main() { let mut val_mut = 1; let _p_mut = &mut val_mut as *mut i32; + + let mut x: [i32; 2] = [42, 43]; + let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); +} + +fn issue_13882() { + let mut x: [i32; 2] = [42, 43]; + let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); } diff --git a/tests/ui/borrow_as_ptr.stderr b/tests/ui/borrow_as_ptr.stderr index ea618b06e2c86..4595fa4f2487a 100644 --- a/tests/ui/borrow_as_ptr.stderr +++ b/tests/ui/borrow_as_ptr.stderr @@ -13,5 +13,17 @@ error: borrow as raw pointer LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)` -error: aborting due to 2 previous errors +error: borrow as raw pointer + --> tests/ui/borrow_as_ptr.rs:21:16 + | +LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])` + +error: borrow as raw pointer + --> tests/ui/borrow_as_ptr.rs:26:17 + | +LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]` + +error: aborting due to 4 previous errors From 34b1765e65054a907dfd4acafb68b0aa4dbf2153 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Dec 2024 20:39:43 +0100 Subject: [PATCH 018/189] Move more def paths into `clippy_utils::paths` --- clippy_lints/src/methods/needless_character_iteration.rs | 3 ++- clippy_lints/src/methods/read_line_without_trim.rs | 3 ++- clippy_utils/src/paths.rs | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 348f740e7ddf7..6993150fb57a5 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -7,6 +7,7 @@ use rustc_span::Span; use super::NEEDLESS_CHARACTER_ITERATION; use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths::CHAR_IS_ASCII; use clippy_utils::source::SpanRangeExt; use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; @@ -77,7 +78,7 @@ fn handle_expr( 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"]) + && match_def_path(cx, fn_def_id, &CHAR_IS_ASCII) && path_to_local_id(peels_expr_ref(arg), first_param) && let Some(snippet) = before_chars.get_source_text(cx) { diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs index db2b9d4d92fb6..82e66a0500a8f 100644 --- a/clippy_lints/src/methods/read_line_without_trim.rs +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -1,6 +1,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths::STDIN; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_local_use_after_expr; @@ -33,7 +34,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool { pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() - && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"]) + && match_def_path(cx, recv_adt.did(), &STDIN) && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind && let Res::Local(local_id) = path.res { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 8cb8cd5901400..f15fffc09e8d9 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -33,6 +33,8 @@ pub const CHILD: [&str; 3] = ["std", "process", "Child"]; pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"]; pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"]; pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; +pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "", "is_ascii"]; +pub const STDIN: [&str; 4] = ["std", "io", "stdio", "Stdin"]; // Paths in clippy itself pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; From a9fe04335a10bdcc5f9921be064e3f4f5f49e31d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 29 Dec 2024 22:18:02 +0100 Subject: [PATCH 019/189] Do not remove identity mapping if mandatory mutability would be lost Removing `.map(identity)` may result in invalid code if the receiver of `map()` is an immutable binding, and the result of `map()` is used as the receiver of a method call expecting a mutable reference. --- clippy_lints/src/methods/map_identity.rs | 15 +++++++++++++-- tests/ui/map_identity.fixed | 15 +++++++++++++++ tests/ui/map_identity.rs | 15 +++++++++++++++ tests/ui/map_identity.stderr | 14 +++++++++++++- 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 1f204de01da06..0536014465731 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method, path_to_local}; +use rustc_ast::BindingMode; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::{Span, sym}; @@ -24,6 +25,16 @@ pub(super) fn check( && is_expr_untyped_identity_function(cx, map_arg) && let Some(sugg_span) = expr.span.trim_start(caller.span) { + // If the result of `.map(identity)` is used as a mutable reference, + // the caller must not be an immutable binding. + if cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr() + && let Some(hir_id) = path_to_local(caller) + && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) + && !matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) + { + return; + } + span_lint_and_sugg( cx, MAP_IDENTITY, diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed index 53ebfb40ba0d2..3257ddc6f72b3 100644 --- a/tests/ui/map_identity.fixed +++ b/tests/ui/map_identity.fixed @@ -61,3 +61,18 @@ fn issue11764() { // no match ergonomics for `(i32, i32)` let _ = x.iter().copied(); } + +fn issue13904() { + // don't lint: `it.next()` would not be legal as `it` is immutable + let it = [1, 2, 3].into_iter(); + let _ = it.map(|x| x).next(); + + // lint + #[allow(unused_mut)] + let mut it = [1, 2, 3].into_iter(); + let _ = it.next(); + + // lint + let it = [1, 2, 3].into_iter(); + let _ = { it }.next(); +} diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs index c646c0568595e..be3bb9a4f1068 100644 --- a/tests/ui/map_identity.rs +++ b/tests/ui/map_identity.rs @@ -65,3 +65,18 @@ fn issue11764() { // no match ergonomics for `(i32, i32)` let _ = x.iter().copied().map(|(x, y)| (x, y)); } + +fn issue13904() { + // don't lint: `it.next()` would not be legal as `it` is immutable + let it = [1, 2, 3].into_iter(); + let _ = it.map(|x| x).next(); + + // lint + #[allow(unused_mut)] + let mut it = [1, 2, 3].into_iter(); + let _ = it.map(|x| x).next(); + + // lint + let it = [1, 2, 3].into_iter(); + let _ = { it }.map(|x| x).next(); +} diff --git a/tests/ui/map_identity.stderr b/tests/ui/map_identity.stderr index 0a0dc9c8f075b..aa3fc4ae0b5c4 100644 --- a/tests/ui/map_identity.stderr +++ b/tests/ui/map_identity.stderr @@ -73,5 +73,17 @@ error: unnecessary map of the identity function LL | let _ = x.iter().copied().map(|(x, y)| (x, y)); | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` -error: aborting due to 11 previous errors +error: unnecessary map of the identity function + --> tests/ui/map_identity.rs:77:15 + | +LL | let _ = it.map(|x| x).next(); + | ^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> tests/ui/map_identity.rs:81:19 + | +LL | let _ = { it }.map(|x| x).next(); + | ^^^^^^^^^^^ help: remove the call to `map` + +error: aborting due to 13 previous errors From e4b11a72665732989fc01f8f140b25469790608b Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 29 Dec 2024 23:07:33 +0100 Subject: [PATCH 020/189] =?UTF-8?q?Fix=20parentheses=20when=20replacing=20?= =?UTF-8?q?`matches!(=E2=80=A6,=20None)`=20with=20`.is=5Fnone()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clippy_lints/src/matches/redundant_pattern_match.rs | 8 +++++--- tests/ui/redundant_pattern_matching_option.fixed | 8 ++++++++ tests/ui/redundant_pattern_matching_option.rs | 8 ++++++++ tests/ui/redundant_pattern_matching_option.stderr | 8 +++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 264458a86ef49..897e3f5f7f2c5 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,6 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, walk_span_to_context}; +use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; @@ -274,7 +274,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op ExprKind::AddrOf(_, _, borrowed) => borrowed, _ => op, }; - let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_")); + let mut app = Applicability::MachineApplicable; + let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par(); + let mut sugg = format!("{receiver_sugg}.{good_method}"); if let Some(guard) = maybe_guard { // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying! @@ -307,7 +309,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op format!("redundant pattern matching, consider using `{good_method}`"), "try", sugg, - Applicability::MachineApplicable, + app, ); } } diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index c9b76262d70b4..c7e0cd2610f0e 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -137,3 +137,11 @@ fn issue10803() { // Don't lint let _ = matches!(x, Some(16)); } + +fn issue13902() { + let x = Some(0); + let p = &raw const x; + unsafe { + let _ = (*p).is_none(); + } +} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index a5f9caf659c61..6d9a9f7f9428b 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -164,3 +164,11 @@ fn issue10803() { // Don't lint let _ = matches!(x, Some(16)); } + +fn issue13902() { + let x = Some(0); + let p = &raw const x; + unsafe { + let _ = matches!(*p, None); + } +} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 575f199be42c5..34d80f5ca7820 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -209,5 +209,11 @@ error: redundant pattern matching, consider using `is_none()` LL | let _ = matches!(x, None); | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` -error: aborting due to 30 previous errors +error: redundant pattern matching, consider using `is_none()` + --> tests/ui/redundant_pattern_matching_option.rs:172:17 + | +LL | let _ = matches!(*p, None); + | ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()` + +error: aborting due to 31 previous errors From a657fcc89a1d2b3badc50f101818b8fcd6f220fd Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 29 Dec 2024 23:58:42 +0100 Subject: [PATCH 021/189] Use the full lifetime name in suggestions Using `lifetime.ident.name` in suggestions will not output the raw modifier. For example, `'r#struct` will be rendered as `'struct` which would be incorrect. --- clippy_lints/src/needless_arbitrary_self_type.rs | 7 +++++-- tests/ui/needless_arbitrary_self_type.fixed | 5 +++++ tests/ui/needless_arbitrary_self_type.rs | 5 +++++ tests/ui/needless_arbitrary_self_type.stderr | 14 +++++++++++++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 3c47d0edfdc5b..5f7fde30f03f6 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -80,7 +81,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod applicability = Applicability::HasPlaceholders; "&'_ mut self".to_string() } else { - format!("&{} mut self", &lifetime.ident.name) + let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability); + format!("&{lt_name} mut self") } }, (Mode::Ref(None), Mutability::Not) => "&self".to_string(), @@ -89,7 +91,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod applicability = Applicability::HasPlaceholders; "&'_ self".to_string() } else { - format!("&{} self", &lifetime.ident.name) + let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability); + format!("&{lt_name} self") } }, (Mode::Value, Mutability::Mut) => "mut self".to_string(), diff --git a/tests/ui/needless_arbitrary_self_type.fixed b/tests/ui/needless_arbitrary_self_type.fixed index 9da60c687d444..530eb77d83d28 100644 --- a/tests/ui/needless_arbitrary_self_type.fixed +++ b/tests/ui/needless_arbitrary_self_type.fixed @@ -64,4 +64,9 @@ impl ValType { } } +trait Foo<'r#struct> { + fn f1(&'r#struct self) {} + fn f2(&'r#struct mut self) {} +} + fn main() {} diff --git a/tests/ui/needless_arbitrary_self_type.rs b/tests/ui/needless_arbitrary_self_type.rs index fc4ec5cb0b3ca..5a1ff96a11cc2 100644 --- a/tests/ui/needless_arbitrary_self_type.rs +++ b/tests/ui/needless_arbitrary_self_type.rs @@ -64,4 +64,9 @@ impl ValType { } } +trait Foo<'r#struct> { + fn f1(self: &'r#struct Self) {} + fn f2(self: &'r#struct mut Self) {} +} + fn main() {} diff --git a/tests/ui/needless_arbitrary_self_type.stderr b/tests/ui/needless_arbitrary_self_type.stderr index c653267f7525b..7ebbbaa122f51 100644 --- a/tests/ui/needless_arbitrary_self_type.stderr +++ b/tests/ui/needless_arbitrary_self_type.stderr @@ -37,5 +37,17 @@ error: the type of the `self` parameter does not need to be arbitrary LL | pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) { | ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self` -error: aborting due to 6 previous errors +error: the type of the `self` parameter does not need to be arbitrary + --> tests/ui/needless_arbitrary_self_type.rs:68:11 + | +LL | fn f1(self: &'r#struct Self) {} + | ^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct self` + +error: the type of the `self` parameter does not need to be arbitrary + --> tests/ui/needless_arbitrary_self_type.rs:69:11 + | +LL | fn f2(self: &'r#struct mut Self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct mut self` + +error: aborting due to 8 previous errors From 5966ba0424e75accc4be35c2e334791a98c23aaf Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 30 Dec 2024 00:26:47 +0100 Subject: [PATCH 022/189] Fix ptr::from_ref documentation example comment The comment says that the expression involves no function call, but that was only true for the example above, the example here _does_ contain a function call. --- library/core/src/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index e6e13eaff7b0f..d2b60f06e4559 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -777,7 +777,7 @@ pub fn with_exposed_provenance_mut(addr: usize) -> *mut T { /// # type T = i32; /// # fn foo() -> T { 42 } /// // The temporary holding the return value of `foo` does *not* have its lifetime extended, -/// // because the surrounding expression involves no function call. +/// // because the surrounding expression involves a function call. /// let p = ptr::from_ref(&foo()); /// unsafe { p.read() }; // UB! Reading from a dangling pointer ⚠️ /// ``` @@ -828,7 +828,7 @@ pub const fn from_ref(r: &T) -> *const T { /// # type T = i32; /// # fn foo() -> T { 42 } /// // The temporary holding the return value of `foo` does *not* have its lifetime extended, -/// // because the surrounding expression involves no function call. +/// // because the surrounding expression involves a function call. /// let p = ptr::from_mut(&mut foo()); /// unsafe { p.write(T::default()) }; // UB! Writing to a dangling pointer ⚠️ /// ``` From b515064fd2c9e5ed6d869e85a590389d19f38f3a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 30 Dec 2024 12:28:47 +0100 Subject: [PATCH 023/189] Correctly handle `char` paths --- clippy_lints/src/utils/internal_lints/invalid_paths.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index a5fad68eea189..08c178ed229fd 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -73,6 +73,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { SimplifiedType::Slice, SimplifiedType::Str, SimplifiedType::Bool, + SimplifiedType::Char, ] .iter() .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter()) From 48993338863688fdfadda10931af62b3fd7cfa92 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Tue, 31 Dec 2024 15:46:11 +0900 Subject: [PATCH 024/189] better suggestion for slow_vector_initialization --- .../src/slow_vector_initialization.rs | 22 +-- tests/ui/slow_vector_initialization.rs | 26 ++-- tests/ui/slow_vector_initialization.stderr | 143 ++++++++++-------- 3 files changed, 104 insertions(+), 87 deletions(-) diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 8c8f11569c8c2..d2d693eaa1f38 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ @@ -203,14 +203,18 @@ impl SlowVectorInit { "len", ); - span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| { - diag.span_suggestion( - vec_alloc.allocation_expr.span.source_callsite(), - "consider replacing this with", - format!("vec![0; {len_expr}]"), - Applicability::Unspecified, - ); - }); + let span_to_replace = slow_fill + .span + .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo()); + span_lint_and_sugg( + cx, + SLOW_VECTOR_INITIALIZATION, + span_to_replace, + msg, + "consider replacing this with", + format!("vec![0; {len_expr}]"), + Applicability::Unspecified, + ); } } diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs index 16f81019574fb..2ba87f4125000 100644 --- a/tests/ui/slow_vector_initialization.rs +++ b/tests/ui/slow_vector_initialization.rs @@ -11,22 +11,22 @@ fn extend_vector() { // Extend with constant expression let len = 300; let mut vec1 = Vec::with_capacity(len); - vec1.extend(repeat(0).take(len)); //~^ ERROR: slow zero-filling initialization //~| NOTE: `-D clippy::slow-vector-initialization` implied by `-D warnings` + vec1.extend(repeat(0).take(len)); // Extend with len expression let mut vec2 = Vec::with_capacity(len - 10); - vec2.extend(repeat(0).take(len - 10)); //~^ ERROR: slow zero-filling initialization + vec2.extend(repeat(0).take(len - 10)); // Extend with mismatching expression should not be warned let mut vec3 = Vec::with_capacity(24322); vec3.extend(repeat(0).take(2)); let mut vec4 = Vec::with_capacity(len); - vec4.extend(repeat(0).take(vec4.capacity())); //~^ ERROR: slow zero-filling initialization + vec4.extend(repeat(0).take(vec4.capacity())); } fn mixed_extend_resize_vector() { @@ -36,20 +36,20 @@ fn mixed_extend_resize_vector() { // Slow initialization let mut resized_vec = Vec::with_capacity(30); - resized_vec.resize(30, 0); //~^ ERROR: slow zero-filling initialization + resized_vec.resize(30, 0); let mut extend_vec = Vec::with_capacity(30); - extend_vec.extend(repeat(0).take(30)); //~^ ERROR: slow zero-filling initialization + extend_vec.extend(repeat(0).take(30)); } fn resize_vector() { // Resize with constant expression let len = 300; let mut vec1 = Vec::with_capacity(len); - vec1.resize(len, 0); //~^ ERROR: slow zero-filling initialization + vec1.resize(len, 0); // Resize mismatch len let mut vec2 = Vec::with_capacity(200); @@ -57,39 +57,39 @@ fn resize_vector() { // Resize with len expression let mut vec3 = Vec::with_capacity(len - 10); - vec3.resize(len - 10, 0); //~^ ERROR: slow zero-filling initialization + vec3.resize(len - 10, 0); let mut vec4 = Vec::with_capacity(len); - vec4.resize(vec4.capacity(), 0); //~^ ERROR: slow zero-filling initialization + vec4.resize(vec4.capacity(), 0); // Reinitialization should be warned vec1 = Vec::with_capacity(10); - vec1.resize(10, 0); //~^ ERROR: slow zero-filling initialization + vec1.resize(10, 0); } fn from_empty_vec() { // Resize with constant expression let len = 300; let mut vec1 = Vec::new(); - vec1.resize(len, 0); //~^ ERROR: slow zero-filling initialization + vec1.resize(len, 0); // Resize with len expression let mut vec3 = Vec::new(); - vec3.resize(len - 10, 0); //~^ ERROR: slow zero-filling initialization + vec3.resize(len - 10, 0); // Reinitialization should be warned vec1 = Vec::new(); - vec1.resize(10, 0); //~^ ERROR: slow zero-filling initialization + vec1.resize(10, 0); vec1 = vec![]; - vec1.resize(10, 0); //~^ ERROR: slow zero-filling initialization + vec1.resize(10, 0); macro_rules! x { () => { diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index 353c677097be7..7f4b9f7b67a41 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -1,109 +1,122 @@ error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:14:5 + --> tests/ui/slow_vector_initialization.rs:13:20 | -LL | let mut vec1 = Vec::with_capacity(len); - | ----------------------- help: consider replacing this with: `vec![0; len]` -LL | vec1.extend(repeat(0).take(len)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut vec1 = Vec::with_capacity(len); + | ____________________^ +... | +LL | | vec1.extend(repeat(0).take(len)); + | |____________________________________^ help: consider replacing this with: `vec![0; len]` | = note: `-D clippy::slow-vector-initialization` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:20:5 + --> tests/ui/slow_vector_initialization.rs:19:20 | -LL | let mut vec2 = Vec::with_capacity(len - 10); - | ---------------------------- help: consider replacing this with: `vec![0; len - 10]` -LL | vec2.extend(repeat(0).take(len - 10)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut vec2 = Vec::with_capacity(len - 10); + | ____________________^ +LL | | +LL | | vec2.extend(repeat(0).take(len - 10)); + | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:28:5 + --> tests/ui/slow_vector_initialization.rs:27:20 | -LL | let mut vec4 = Vec::with_capacity(len); - | ----------------------- help: consider replacing this with: `vec![0; len]` -LL | vec4.extend(repeat(0).take(vec4.capacity())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut vec4 = Vec::with_capacity(len); + | ____________________^ +LL | | +LL | | vec4.extend(repeat(0).take(vec4.capacity())); + | |________________________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:39:5 + --> tests/ui/slow_vector_initialization.rs:38:27 | -LL | let mut resized_vec = Vec::with_capacity(30); - | ---------------------- help: consider replacing this with: `vec![0; 30]` -LL | resized_vec.resize(30, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut resized_vec = Vec::with_capacity(30); + | ___________________________^ +LL | | +LL | | resized_vec.resize(30, 0); + | |_____________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:43:5 + --> tests/ui/slow_vector_initialization.rs:42:26 | -LL | let mut extend_vec = Vec::with_capacity(30); - | ---------------------- help: consider replacing this with: `vec![0; 30]` -LL | extend_vec.extend(repeat(0).take(30)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut extend_vec = Vec::with_capacity(30); + | __________________________^ +LL | | +LL | | extend_vec.extend(repeat(0).take(30)); + | |_________________________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:51:5 + --> tests/ui/slow_vector_initialization.rs:50:20 | -LL | let mut vec1 = Vec::with_capacity(len); - | ----------------------- help: consider replacing this with: `vec![0; len]` -LL | vec1.resize(len, 0); - | ^^^^^^^^^^^^^^^^^^^ +LL | let mut vec1 = Vec::with_capacity(len); + | ____________________^ +LL | | +LL | | vec1.resize(len, 0); + | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:60:5 + --> tests/ui/slow_vector_initialization.rs:59:20 | -LL | let mut vec3 = Vec::with_capacity(len - 10); - | ---------------------------- help: consider replacing this with: `vec![0; len - 10]` -LL | vec3.resize(len - 10, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut vec3 = Vec::with_capacity(len - 10); + | ____________________^ +LL | | +LL | | vec3.resize(len - 10, 0); + | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:64:5 + --> tests/ui/slow_vector_initialization.rs:63:20 | -LL | let mut vec4 = Vec::with_capacity(len); - | ----------------------- help: consider replacing this with: `vec![0; len]` -LL | vec4.resize(vec4.capacity(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut vec4 = Vec::with_capacity(len); + | ____________________^ +LL | | +LL | | vec4.resize(vec4.capacity(), 0); + | |___________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:69:5 + --> tests/ui/slow_vector_initialization.rs:68:12 | -LL | vec1 = Vec::with_capacity(10); - | ---------------------- help: consider replacing this with: `vec![0; 10]` -LL | vec1.resize(10, 0); - | ^^^^^^^^^^^^^^^^^^ +LL | vec1 = Vec::with_capacity(10); + | ____________^ +LL | | +LL | | vec1.resize(10, 0); + | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:77:5 + --> tests/ui/slow_vector_initialization.rs:76:20 | -LL | let mut vec1 = Vec::new(); - | ---------- help: consider replacing this with: `vec![0; len]` -LL | vec1.resize(len, 0); - | ^^^^^^^^^^^^^^^^^^^ +LL | let mut vec1 = Vec::new(); + | ____________________^ +LL | | +LL | | vec1.resize(len, 0); + | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:82:5 + --> tests/ui/slow_vector_initialization.rs:81:20 | -LL | let mut vec3 = Vec::new(); - | ---------- help: consider replacing this with: `vec![0; len - 10]` -LL | vec3.resize(len - 10, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut vec3 = Vec::new(); + | ____________________^ +LL | | +LL | | vec3.resize(len - 10, 0); + | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:87:5 + --> tests/ui/slow_vector_initialization.rs:86:12 | -LL | vec1 = Vec::new(); - | ---------- help: consider replacing this with: `vec![0; 10]` -LL | vec1.resize(10, 0); - | ^^^^^^^^^^^^^^^^^^ +LL | vec1 = Vec::new(); + | ____________^ +LL | | +LL | | vec1.resize(10, 0); + | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:91:5 + --> tests/ui/slow_vector_initialization.rs:90:12 | -LL | vec1 = vec![]; - | ------ help: consider replacing this with: `vec![0; 10]` -LL | vec1.resize(10, 0); - | ^^^^^^^^^^^^^^^^^^ +LL | vec1 = vec![]; + | ____________^ +LL | | +LL | | vec1.resize(10, 0); + | |______________________^ help: consider replacing this with: `vec![0; 10]` error: aborting due to 13 previous errors From 1e0b782a63d9b783bb1ec4bdd5cfb7747b914eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 31 Dec 2024 12:00:19 +0100 Subject: [PATCH 025/189] add test for ICE `asked to assemble constituent types of unexpected type: Binder(Foo, [])` Fixes #10972 --- tests/ui/crashes/ice-10972-tait.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/ui/crashes/ice-10972-tait.rs diff --git a/tests/ui/crashes/ice-10972-tait.rs b/tests/ui/crashes/ice-10972-tait.rs new file mode 100644 index 0000000000000..f3ab9cebb7c26 --- /dev/null +++ b/tests/ui/crashes/ice-10972-tait.rs @@ -0,0 +1,9 @@ +// ICE: #10972 +// asked to assemble constituent types of unexpected type: Binder(Foo, []) +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; +type Foo = impl Debug; +const FOO2: Foo = 22_u32; + +pub fn main() {} From 2a4dadd9854ad2d52dc1c10a860cd4ddb134567f Mon Sep 17 00:00:00 2001 From: A_A <21040751+Otto-AA@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:47:12 +0100 Subject: [PATCH 026/189] fix type suggestion for manual_is_ascii_check (#13913) --- clippy_lints/src/manual_is_ascii_check.rs | 13 +++++------- tests/ui/manual_is_ascii_check.fixed | 5 +++++ tests/ui/manual_is_ascii_check.rs | 5 +++++ tests/ui/manual_is_ascii_check.stderr | 24 ++++++++++++++++++++++- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 3f01f3cf30aea..2c25f098851dd 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -123,18 +123,15 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { extract_msrv_attr!(LateContext); } -fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> { - if let ExprKind::Lit(lit) = bound_expr.kind +fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, String)> { + if let ExprKind::Lit(_) = bound_expr.kind && let local_hid = path_to_local(arg)? && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given && ty_span == span { - let ty_str = match lit.node { - Char(_) => "char", - Byte(_) => "u8", - _ => return None, - }; + let arg_type = cx.typeck_results().expr_ty(arg); + let ty_str = arg_type.to_string(); return Some((*ty_span, ty_str)); } None @@ -145,7 +142,7 @@ fn check_is_ascii( span: Span, recv: &Expr<'_>, range: &CharRange, - ty_sugg: Option<(Span, &'_ str)>, + ty_sugg: Option<(Span, String)>, ) { let sugg = match range { CharRange::UpperChar => "is_ascii_uppercase", diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index a72caa3a37ee6..179149f697db6 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -82,3 +82,8 @@ fn generics() { take_while(|c: u8| c.is_ascii_uppercase()); take_while(|c: char| c.is_ascii_uppercase()); } + +fn adds_type_reference() { + let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect(); + let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); +} diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index bb6e2a317da16..74f35ce94e84b 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -82,3 +82,8 @@ fn generics() { take_while(|c| (b'A'..=b'Z').contains(&c)); take_while(|c: char| ('A'..='Z').contains(&c)); } + +fn adds_type_reference() { + let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect(); + let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect(); +} diff --git a/tests/ui/manual_is_ascii_check.stderr b/tests/ui/manual_is_ascii_check.stderr index a93ccace28a6e..92d93208006ad 100644 --- a/tests/ui/manual_is_ascii_check.stderr +++ b/tests/ui/manual_is_ascii_check.stderr @@ -173,5 +173,27 @@ error: manual check for common ascii range LL | take_while(|c: char| ('A'..='Z').contains(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()` -error: aborting due to 27 previous errors +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:87:63 + | +LL | let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL | let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect(); + | ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:88:71 + | +LL | let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL | let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); + | ~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ + +error: aborting due to 29 previous errors From 3bc089e9fed025974a7a859258c8b7a293f4e7c5 Mon Sep 17 00:00:00 2001 From: A_A <21040751+Otto-AA@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:18:43 +0100 Subject: [PATCH 027/189] refactor manual_is_ascii_check to remove unused parameter --- clippy_lints/src/manual_is_ascii_check.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 2c25f098851dd..091203184b6fb 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_)) { let arg = peel_ref_operators(cx, arg); - let ty_sugg = get_ty_sugg(cx, arg, start); + let ty_sugg = get_ty_sugg(cx, arg); let range = check_range(start, end); check_is_ascii(cx, expr.span, arg, &range, ty_sugg); } @@ -123,10 +123,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { extract_msrv_attr!(LateContext); } -fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, String)> { - if let ExprKind::Lit(_) = bound_expr.kind - && let local_hid = path_to_local(arg)? - && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) +fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>) -> Option<(Span, String)> { + let local_hid = path_to_local(arg)?; + if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given && ty_span == span { From 54e5116b44a1096467991ac7c2851d4c0b7d7361 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Sat, 5 Oct 2024 22:09:20 -0700 Subject: [PATCH 028/189] cover guard patterns in clippy lints --- clippy_lints/src/equatable_if_let.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 8 +++++--- clippy_lints/src/matches/single_match.rs | 4 ++++ clippy_lints/src/utils/author.rs | 6 ++++++ clippy_utils/src/hir_utils.rs | 4 ++++ clippy_utils/src/lib.rs | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index fb9f2b1526e38..9c8edfd6113f6 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), - PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) => unary_pattern(x), + PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } } diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index b72a61a438499..4b731d759723c 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -254,9 +254,11 @@ impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, - PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => { - Self::from_pat(cx, arena, pat) - }, + PatKind::Binding(.., Some(pat)) + | PatKind::Box(pat) + | PatKind::Deref(pat) + | PatKind::Ref(pat, _) + | PatKind::Guard(pat, _) => Self::from_pat(cx, arena, pat), PatKind::Never => Self::Never, PatKind::Struct(ref path, fields, _) => { let fields = diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 3ca20479f8e00..10ca6832d9c12 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -343,6 +343,10 @@ impl<'a> PatState<'a> { matches!(self, Self::Wild) }, + PatKind::Guard(..) => { + matches!(self, Self::Wild) + } + // Patterns for things which can only contain a single sub-pattern. PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => { self.add_pat(cx, pat) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index d2970c93f8e91..c2dcb5ae1f9e5 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -712,6 +712,12 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Ref({pat}, Mutability::{muta:?})"); self.pat(pat); }, + PatKind::Guard(pat, cond) => { + bind!(self, pat, cond); + kind!("Guard({pat}, {cond})"); + self.pat(pat); + self.expr(cond); + } PatKind::Lit(lit_expr) => { bind!(self, lit_expr); kind!("Lit({lit_expr})"); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index ed52c481de124..7c4e834f8416f 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1104,6 +1104,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_pat(pat); std::mem::discriminant(&mu).hash(&mut self.s); }, + PatKind::Guard(pat, guard) => { + self.hash_pat(pat); + self.hash_expr(guard); + }, PatKind::Slice(l, m, r) => { for pat in l { self.hash_pat(pat); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 77c597f853489..4c4e942b2792c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1777,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) => true, + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true, } } From eb7da164081edb3e6119d20ea3855eaf56624aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 30 Dec 2024 10:02:28 +0000 Subject: [PATCH 029/189] move typeck constraints conversion to its own module --- compiler/rustc_borrowck/src/polonius/mod.rs | 42 ++----------------- .../src/polonius/typeck_constraints.rs | 41 ++++++++++++++++++ 2 files changed, 44 insertions(+), 39 deletions(-) create mode 100644 compiler/rustc_borrowck/src/polonius/typeck_constraints.rs diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index a853ff266a119..6ac111410d649 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -37,21 +37,20 @@ mod constraints; mod dump; pub(crate) mod legacy; mod liveness_constraints; +mod typeck_constraints; use std::collections::BTreeMap; use rustc_index::bit_set::SparseBitMatrix; -use rustc_middle::mir::{Body, Location}; +use rustc_middle::mir::Body; use rustc_middle::ty::RegionVid; use rustc_mir_dataflow::points::PointIndex; pub(crate) use self::constraints::*; pub(crate) use self::dump::dump_polonius_mir; use self::liveness_constraints::create_liveness_constraints; +use self::typeck_constraints::convert_typeck_constraints; use crate::RegionInferenceContext; -use crate::constraints::OutlivesConstraint; -use crate::region_infer::values::LivenessValues; -use crate::type_check::Locations; /// This struct holds the data needed to create the Polonius localized constraints. pub(crate) struct PoloniusContext { @@ -117,38 +116,3 @@ impl PoloniusContext { localized_outlives_constraints } } - -/// Propagate loans throughout the subset graph at a given point (with some subtleties around the -/// location where effects start to be visible). -fn convert_typeck_constraints<'tcx>( - body: &Body<'tcx>, - liveness: &LivenessValues, - outlives_constraints: impl Iterator>, - localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet, -) { - for outlives_constraint in outlives_constraints { - match outlives_constraint.locations { - Locations::All(_) => { - // For now, turn logical constraints holding at all points into physical edges at - // every point in the graph. - // FIXME: encode this into *traversal* instead. - for (block, bb) in body.basic_blocks.iter_enumerated() { - let statement_count = bb.statements.len(); - for statement_index in 0..=statement_count { - let current_location = Location { block, statement_index }; - let current_point = liveness.point_from_location(current_location); - - localized_outlives_constraints.push(LocalizedOutlivesConstraint { - source: outlives_constraint.sup, - from: current_point, - target: outlives_constraint.sub, - to: current_point, - }); - } - } - } - - _ => {} - } - } -} diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs new file mode 100644 index 0000000000000..3487c454a74f9 --- /dev/null +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -0,0 +1,41 @@ +use rustc_middle::mir::{Body, Location}; + +use super::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet}; +use crate::constraints::OutlivesConstraint; +use crate::region_infer::values::LivenessValues; +use crate::type_check::Locations; + +/// Propagate loans throughout the subset graph at a given point (with some subtleties around the +/// location where effects start to be visible). +pub(super) fn convert_typeck_constraints<'tcx>( + body: &Body<'tcx>, + liveness: &LivenessValues, + outlives_constraints: impl Iterator>, + localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet, +) { + for outlives_constraint in outlives_constraints { + match outlives_constraint.locations { + Locations::All(_) => { + // For now, turn logical constraints holding at all points into physical edges at + // every point in the graph. + // FIXME: encode this into *traversal* instead. + for (block, bb) in body.basic_blocks.iter_enumerated() { + let statement_count = bb.statements.len(); + for statement_index in 0..=statement_count { + let current_location = Location { block, statement_index }; + let current_point = liveness.point_from_location(current_location); + + localized_outlives_constraints.push(LocalizedOutlivesConstraint { + source: outlives_constraint.sup, + from: current_point, + target: outlives_constraint.sub, + to: current_point, + }); + } + } + } + + _ => {} + } + } +} From 46154b2253f8f6be9e39cd95a304036a6d895d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 30 Dec 2024 10:16:51 +0000 Subject: [PATCH 030/189] localize typeck constraints it's still partially a skeleton, but works well enough for almost all tests to pass --- compiler/rustc_borrowck/src/nll.rs | 6 +- compiler/rustc_borrowck/src/polonius/mod.rs | 5 +- .../src/polonius/typeck_constraints.rs | 194 +++++++++++++++++- 3 files changed, 199 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 968b6d383c1b4..7ae1df9522fb8 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -142,9 +142,9 @@ pub(crate) fn compute_regions<'a, 'tcx>( // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives // constraints. - let localized_outlives_constraints = polonius_context - .as_mut() - .map(|polonius_context| polonius_context.create_localized_constraints(&mut regioncx, body)); + let localized_outlives_constraints = polonius_context.as_mut().map(|polonius_context| { + polonius_context.create_localized_constraints(infcx.tcx, ®ioncx, body) + }); // If requested: dump NLL facts, and run legacy polonius analysis. let polonius_output = all_facts.as_ref().and_then(|all_facts| { diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 6ac111410d649..7d0f9397021be 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -43,7 +43,7 @@ use std::collections::BTreeMap; use rustc_index::bit_set::SparseBitMatrix; use rustc_middle::mir::Body; -use rustc_middle::ty::RegionVid; +use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::points::PointIndex; pub(crate) use self::constraints::*; @@ -87,14 +87,17 @@ impl PoloniusContext { /// - encoding liveness constraints pub(crate) fn create_localized_constraints<'tcx>( &self, + tcx: TyCtxt<'tcx>, regioncx: &RegionInferenceContext<'tcx>, body: &Body<'tcx>, ) -> LocalizedOutlivesConstraintSet { let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default(); convert_typeck_constraints( + tcx, body, regioncx.liveness_constraints(), regioncx.outlives_constraints(), + regioncx.universal_regions(), &mut localized_outlives_constraints, ); diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index 3487c454a74f9..c04661fbbc1a9 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -1,16 +1,22 @@ -use rustc_middle::mir::{Body, Location}; +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::mir::{Body, Location, Statement, StatementKind, Terminator, TerminatorKind}; +use rustc_middle::ty::{TyCtxt, TypeVisitable}; +use rustc_mir_dataflow::points::PointIndex; use super::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet}; use crate::constraints::OutlivesConstraint; use crate::region_infer::values::LivenessValues; use crate::type_check::Locations; +use crate::universal_regions::UniversalRegions; /// Propagate loans throughout the subset graph at a given point (with some subtleties around the /// location where effects start to be visible). pub(super) fn convert_typeck_constraints<'tcx>( + tcx: TyCtxt<'tcx>, body: &Body<'tcx>, liveness: &LivenessValues, outlives_constraints: impl Iterator>, + universal_regions: &UniversalRegions<'tcx>, localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet, ) { for outlives_constraint in outlives_constraints { @@ -35,7 +41,191 @@ pub(super) fn convert_typeck_constraints<'tcx>( } } - _ => {} + Locations::Single(location) => { + // This constraint is marked as holding at one location, we localize it to that + // location or its successor, depending on the corresponding MIR + // statement/terminator. Unfortunately, they all show up from typeck as coming "on + // entry", so for now we modify them to take effects that should apply "on exit" + // into account. + // + // FIXME: this approach is subtle, complicated, and hard to test, so we should track + // this information better in MIR typeck instead, for example with a new `Locations` + // variant that contains which node is crossing over between entry and exit. + let point = liveness.point_from_location(location); + let (from, to) = if let Some(stmt) = + body[location.block].statements.get(location.statement_index) + { + localize_statement_constraint( + tcx, + body, + stmt, + liveness, + &outlives_constraint, + location, + point, + universal_regions, + ) + } else { + assert_eq!(location.statement_index, body[location.block].statements.len()); + let terminator = body[location.block].terminator(); + localize_terminator_constraint( + tcx, + body, + terminator, + liveness, + &outlives_constraint, + point, + universal_regions, + ) + }; + localized_outlives_constraints.push(LocalizedOutlivesConstraint { + source: outlives_constraint.sup, + from, + target: outlives_constraint.sub, + to, + }); + } + } + } +} + +/// For a given outlives constraint arising from a MIR statement, computes the CFG `from`-`to` +/// intra-block nodes to localize the constraint. +fn localize_statement_constraint<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + stmt: &Statement<'tcx>, + liveness: &LivenessValues, + outlives_constraint: &OutlivesConstraint<'tcx>, + current_location: Location, + current_point: PointIndex, + universal_regions: &UniversalRegions<'tcx>, +) -> (PointIndex, PointIndex) { + match &stmt.kind { + StatementKind::Assign(box (lhs, rhs)) => { + // To create localized outlives constraints without midpoints, we rely on the property + // that no input regions from the RHS of the assignment will flow into themselves: they + // should not appear in the output regions in the LHS. We believe this to be true by + // construction of the MIR, via temporaries, and assert it here. + // + // We think we don't need midpoints because: + // - every LHS Place has a unique set of regions that don't appear elsewhere + // - this implies that for them to be part of the RHS, the same Place must be read and + // written + // - and that should be impossible in MIR + // + // When we have a more complete implementation in the future, tested with crater, etc, + // we can relax this to a debug assert instead, or remove it. + assert!( + { + let mut lhs_regions = FxHashSet::default(); + tcx.for_each_free_region(lhs, |region| { + let region = universal_regions.to_region_vid(region); + lhs_regions.insert(region); + }); + + let mut rhs_regions = FxHashSet::default(); + tcx.for_each_free_region(rhs, |region| { + let region = universal_regions.to_region_vid(region); + rhs_regions.insert(region); + }); + + // The intersection between LHS and RHS regions should be empty. + lhs_regions.is_disjoint(&rhs_regions) + }, + "there should be no common regions between the LHS and RHS of an assignment" + ); + + // As mentioned earlier, we should be tracking these better upstream but: we want to + // relate the types on entry to the type of the place on exit. That is, outlives + // constraints on the RHS are on entry, and outlives constraints to/from the LHS are on + // exit (i.e. on entry to the successor location). + let lhs_ty = body.local_decls[lhs.local].ty; + let successor_location = Location { + block: current_location.block, + statement_index: current_location.statement_index + 1, + }; + let successor_point = liveness.point_from_location(successor_location); + compute_constraint_direction( + tcx, + outlives_constraint, + &lhs_ty, + current_point, + successor_point, + universal_regions, + ) + } + _ => { + // For the other cases, we localize an outlives constraint to where it arises. + (current_point, current_point) } } } + +/// For a given outlives constraint arising from a MIR terminator, computes the CFG `from`-`to` +/// inter-block nodes to localize the constraint. +fn localize_terminator_constraint<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + terminator: &Terminator<'tcx>, + liveness: &LivenessValues, + outlives_constraint: &OutlivesConstraint<'tcx>, + current_point: PointIndex, + universal_regions: &UniversalRegions<'tcx>, +) -> (PointIndex, PointIndex) { + // FIXME: check if other terminators need the same handling as `Call`s, in particular + // Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some + // coroutine tests, and that may be why. + match &terminator.kind { + // FIXME: also handle diverging calls. + TerminatorKind::Call { destination, target: Some(target), .. } => { + // Calls are similar to assignments, and thus follow the same pattern. If there is a + // target for the call we also relate what flows into the destination here to entry to + // that successor. + let destination_ty = destination.ty(&body.local_decls, tcx); + let successor_location = Location { block: *target, statement_index: 0 }; + let successor_point = liveness.point_from_location(successor_location); + compute_constraint_direction( + tcx, + outlives_constraint, + &destination_ty, + current_point, + successor_point, + universal_regions, + ) + } + _ => { + // Typeck constraints guide loans between regions at the current point, so we do that in + // the general case, and liveness will take care of making them flow to the terminator's + // successors. + (current_point, current_point) + } + } +} + +/// For a given constraint, returns the `from`-`to` edge according to whether the constraint flows +/// to or from a free region in the given `value`, some kind of result for an effectful operation, +/// like the LHS of an assignment. +fn compute_constraint_direction<'tcx>( + tcx: TyCtxt<'tcx>, + outlives_constraint: &OutlivesConstraint<'tcx>, + value: &impl TypeVisitable>, + current_point: PointIndex, + successor_point: PointIndex, + universal_regions: &UniversalRegions<'tcx>, +) -> (PointIndex, PointIndex) { + let mut to = current_point; + let mut from = current_point; + tcx.for_each_free_region(value, |region| { + let region = universal_regions.to_region_vid(region); + if region == outlives_constraint.sub { + // This constraint flows into the result, its effects start becoming visible on exit. + to = successor_point; + } else if region == outlives_constraint.sup { + // This constraint flows from the result, its effects start becoming visible on exit. + from = successor_point; + } + }); + + (from, to) +} From 56e7575ddd00ad4754493c66891810bf9095cd65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 30 Dec 2024 11:05:15 +0000 Subject: [PATCH 031/189] move `find_assignments` to its only use site this is to remove the entire `util` module --- .../src/diagnostics/mutability_errors.rs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index c690789b587f6..ad887b7e5eef2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -10,6 +10,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, BindingMode, ByRef, Node}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; +use rustc_middle::mir::visit::PlaceContext; use rustc_middle::mir::{ self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location, Mutability, Place, PlaceRef, ProjectionElem, @@ -22,7 +23,6 @@ use rustc_trait_selection::traits; use tracing::debug; use crate::diagnostics::BorrowedContentSource; -use crate::util::FindAssignments; use crate::{MirBorrowckCtxt, session_diagnostics}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -1084,6 +1084,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } + /// Finds all statements that assign directly to local (i.e., X = ...) and returns their + /// locations. + fn find_assignments(&self, local: Local) -> Vec { + use rustc_middle::mir::visit::Visitor; + + struct FindLocalAssignmentVisitor { + needle: Local, + locations: Vec, + } + + impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { + fn visit_local( + &mut self, + local: Local, + place_context: PlaceContext, + location: Location, + ) { + if self.needle != local { + return; + } + + if place_context.is_place_assignment() { + self.locations.push(location); + } + } + } + + let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; + visitor.visit_body(self.body); + visitor.locations + } + fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) { let local_decl = &self.body.local_decls[local]; @@ -1117,7 +1149,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { })) => { // check if the RHS is from desugaring let opt_assignment_rhs_span = - self.body.find_assignments(local).first().map(|&location| { + self.find_assignments(local).first().map(|&location| { if let Some(mir::Statement { source_info: _, kind: From ff1aaa52ff5deadcb94995978b894aba3b7c8a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 30 Dec 2024 11:06:54 +0000 Subject: [PATCH 032/189] remove empty `util` module --- compiler/rustc_borrowck/src/lib.rs | 1 - .../rustc_borrowck/src/util/collect_writes.rs | 35 ------------------- compiler/rustc_borrowck/src/util/mod.rs | 3 -- 3 files changed, 39 deletions(-) delete mode 100644 compiler/rustc_borrowck/src/util/collect_writes.rs delete mode 100644 compiler/rustc_borrowck/src/util/mod.rs diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index b061a450c83f7..61934eba8467b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -81,7 +81,6 @@ mod session_diagnostics; mod type_check; mod universal_regions; mod used_muts; -mod util; /// A public API provided for the Rust compiler consumers. pub mod consumers; diff --git a/compiler/rustc_borrowck/src/util/collect_writes.rs b/compiler/rustc_borrowck/src/util/collect_writes.rs deleted file mode 100644 index 55f1073176aef..0000000000000 --- a/compiler/rustc_borrowck/src/util/collect_writes.rs +++ /dev/null @@ -1,35 +0,0 @@ -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location}; - -pub(crate) trait FindAssignments { - // Finds all statements that assign directly to local (i.e., X = ...) - // and returns their locations. - fn find_assignments(&self, local: Local) -> Vec; -} - -impl<'tcx> FindAssignments for Body<'tcx> { - fn find_assignments(&self, local: Local) -> Vec { - let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; - visitor.visit_body(self); - visitor.locations - } -} - -// The Visitor walks the MIR to return the assignment statements corresponding -// to a Local. -struct FindLocalAssignmentVisitor { - needle: Local, - locations: Vec, -} - -impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { - fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { - if self.needle != local { - return; - } - - if place_context.is_place_assignment() { - self.locations.push(location); - } - } -} diff --git a/compiler/rustc_borrowck/src/util/mod.rs b/compiler/rustc_borrowck/src/util/mod.rs deleted file mode 100644 index 5f2960b768b29..0000000000000 --- a/compiler/rustc_borrowck/src/util/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod collect_writes; - -pub(crate) use collect_writes::FindAssignments; From 79d761d93c57ac8cc01ae053770f86752402b445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 30 Dec 2024 11:12:53 +0000 Subject: [PATCH 033/189] remove `allow_two_phase_borrow` it's been simplified over the years, but now it's no longer useful. - document its replacement in `BorrowKind` - use that everywhere instead --- compiler/rustc_borrowck/src/borrow_set.rs | 3 +-- compiler/rustc_borrowck/src/lib.rs | 4 ++-- compiler/rustc_borrowck/src/path_utils.rs | 9 +-------- .../src/polonius/legacy/loan_invalidations.rs | 4 ++-- compiler/rustc_middle/src/mir/statement.rs | 2 ++ 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index ff838fbbb8868..a29833464fb86 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -11,7 +11,6 @@ use rustc_mir_dataflow::move_paths::MoveData; use tracing::debug; use crate::BorrowIndex; -use crate::path_utils::allow_two_phase_borrow; use crate::place_ext::PlaceExt; pub struct BorrowSet<'tcx> { @@ -350,7 +349,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { start_location, assigned_place, borrow_index, ); - if !allow_two_phase_borrow(kind) { + if !kind.allows_two_phase_borrow() { debug!(" -> {:?}", start_location); return; } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 61934eba8467b..3a81c2660b13e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1076,7 +1076,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { - assert!(allow_two_phase_borrow(borrow.kind)); + assert!(borrow.kind.allows_two_phase_borrow()); return Control::Continue; } @@ -1184,7 +1184,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(bk) { + if bk.allows_two_phase_borrow() { (Deep, Reservation(wk)) } else { (Deep, Write(wk)) diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 12a37f56fcf96..257ff1fb3cded 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -1,19 +1,12 @@ use rustc_abi::FieldIdx; use rustc_data_structures::graph::dominators::Dominators; -use rustc_middle::mir::{BasicBlock, Body, BorrowKind, Location, Place, PlaceRef, ProjectionElem}; +use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::TyCtxt; use tracing::debug; use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; use crate::{AccessDepth, BorrowIndex, places_conflict}; -/// Returns `true` if the borrow represented by `kind` is -/// allowed to be split into separate Reservation and -/// Activation phases. -pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool { - kind.allows_two_phase_borrow() -} - /// Control for the path borrow checking code #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(super) enum Control { diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index bb6d593d0d88e..1602f8cbd6175 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -260,7 +260,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { } BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(bk) { + if bk.allows_two_phase_borrow() { (Deep, Reservation(wk)) } else { (Deep, Write(wk)) @@ -378,7 +378,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it - assert!(allow_two_phase_borrow(borrow.kind)); + assert!(borrow.kind.allows_two_phase_borrow()); return Control::Continue; } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index da3fa9e324a4d..470a247d794ec 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -455,6 +455,8 @@ impl BorrowKind { } } + /// Returns whether borrows represented by this kind are allowed to be split into separate + /// Reservation and Activation phases. pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared From 9d444c26c9e3cac3ceea14a6da1bc1d27d7075a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 30 Dec 2024 11:27:24 +0000 Subject: [PATCH 034/189] remove borrowck duplicate of `std::ops::ControlFlow` --- compiler/rustc_borrowck/src/lib.rs | 16 ++++++++-------- compiler/rustc_borrowck/src/path_utils.rs | 13 ++++--------- .../src/polonius/legacy/loan_invalidations.rs | 6 ++++-- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3a81c2660b13e..c97c3f3f87035 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -17,7 +17,7 @@ use std::cell::RefCell; use std::marker::PhantomData; -use std::ops::Deref; +use std::ops::{ControlFlow, Deref}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -1053,31 +1053,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { rw, (borrow_index, borrow), ); - Control::Continue + ControlFlow::Continue(()) } (Read(_), BorrowKind::Shared | BorrowKind::Fake(_)) | ( Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))), BorrowKind::Mut { .. }, - ) => Control::Continue, + ) => ControlFlow::Continue(()), (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be // disallowed on NLL). See rust-lang/rust#56254 - Control::Continue + ControlFlow::Continue(()) } (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => { // Handled by initialization checks. - Control::Continue + ControlFlow::Continue(()) } (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { assert!(borrow.kind.allows_two_phase_borrow()); - return Control::Continue; + return ControlFlow::Continue(()); } error_reported = true; @@ -1093,7 +1093,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { this.buffer_error(err); } } - Control::Break + ControlFlow::Break(()) } (Reservation(kind) | Activation(kind, _) | Write(kind), _) => { @@ -1140,7 +1140,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { this.report_illegal_mutation_of_borrowed(location, place_span, borrow) } } - Control::Break + ControlFlow::Break(()) } }, ); diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 257ff1fb3cded..2c94a32d369ce 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -1,3 +1,5 @@ +use std::ops::ControlFlow; + use rustc_abi::FieldIdx; use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem}; @@ -7,13 +9,6 @@ use tracing::debug; use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; use crate::{AccessDepth, BorrowIndex, places_conflict}; -/// Control for the path borrow checking code -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum Control { - Continue, - Break, -} - /// Encapsulates the idea of iterating over every borrow that involves a particular path pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( s: &mut S, @@ -24,7 +19,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( is_candidate: I, mut op: F, ) where - F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control, + F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> ControlFlow<()>, I: Fn(BorrowIndex) -> bool, { let (access, place) = access_place; @@ -55,7 +50,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( i, borrowed, place, access ); let ctrl = op(s, i, borrowed); - if ctrl == Control::Break { + if matches!(ctrl, ControlFlow::Break(_)) { return; } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 1602f8cbd6175..3c3b93cdc0d3b 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -1,3 +1,5 @@ +use std::ops::ControlFlow; + use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::bug; use rustc_middle::mir::visit::Visitor; @@ -379,7 +381,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { if !is_active(this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it assert!(borrow.kind.allows_two_phase_borrow()); - return Control::Continue; + return ControlFlow::Continue(()); } // Unique and mutable borrows are invalidated by reads from any @@ -395,7 +397,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { this.emit_loan_invalidated_at(borrow_index, location); } } - Control::Continue + ControlFlow::Continue(()) }, ); } From 4c9c2cca2b3fdb0e926ca41555c27e53dff6b9a6 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 24 Dec 2024 00:01:39 +0100 Subject: [PATCH 035/189] Check if deref target implements `is_empty` for `len_zero` lint In this case, the lint can be triggered as well as `is_empty()` will be found on the target type. --- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/len_zero.rs | 39 ++++++++++++++++++---------- tests/ui/len_zero.fixed | 22 ++++++++++++++++ tests/ui/len_zero.rs | 22 ++++++++++++++++ tests/ui/len_zero.stderr | 42 ++++++++++++++++++------------- 5 files changed, 95 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 8c22e43349f62..f658e5d7922cd 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -182,7 +182,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when // T is a generic type. For example, return type of `Option::as_deref()` is a generic. // So we have a hack like this. - && generic_args.len() > 0 + && !generic_args.is_empty() { return; } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 3ea758e176f0b..fb93a195b8322 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use clippy_utils::ty::implements_trait; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -620,18 +621,30 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { }) } - let ty = &cx.typeck_results().expr_ty(expr).peel_refs(); - match ty.kind() { - ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| { - let is_empty = sym!(is_empty); - cx.tcx - .associated_items(principal.def_id()) - .filter_by_name_unhygienic(is_empty) - .any(|item| is_is_empty(cx, item)) - }), - ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id), - ty::Adt(id, _) => has_is_empty_impl(cx, id.did()), - ty::Array(..) | ty::Slice(..) | ty::Str => true, - _ => false, + fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool { + match ty.kind() { + ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| { + let is_empty = sym!(is_empty); + cx.tcx + .associated_items(principal.def_id()) + .filter_by_name_unhygienic(is_empty) + .any(|item| is_is_empty(cx, item)) + }), + ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id), + ty::Adt(id, _) => { + has_is_empty_impl(cx, id.did()) + || (cx.tcx.recursion_limit().value_within_limit(depth) + && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| { + implements_trait(cx, ty, deref_id, &[]) + && cx + .get_associated_type(ty, deref_id, "Target") + .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1)) + })) + }, + ty::Array(..) | ty::Slice(..) | ty::Str => true, + _ => false, + } } + + ty_has_is_empty(cx, cx.typeck_results().expr_ty(expr).peel_refs(), 0) } diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 27319d9c20e8b..c9c476ba4214b 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -108,6 +108,8 @@ fn main() { let d2s = DerefToDerefToString {}; println!("{}", (**d2s).is_empty()); + println!("{}", std::borrow::Cow::Borrowed("").is_empty()); + let y = One; if y.len() == 0 { // No error; `One` does not have `.is_empty()`. @@ -226,3 +228,23 @@ fn binop_with_macros() { (!has_is_empty.is_empty()).then(|| println!("This can happen.")); } + +fn no_infinite_recursion() -> bool { + struct S; + + impl Deref for S { + type Target = Self; + fn deref(&self) -> &Self::Target { + self + } + } + + impl PartialEq<&'static str> for S { + fn eq(&self, _other: &&'static str) -> bool { + false + } + } + + // Do not crash while checking if S implements `.is_empty()` + S == "" +} diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 03c05bc6ed7b2..610a5448d10eb 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -108,6 +108,8 @@ fn main() { let d2s = DerefToDerefToString {}; println!("{}", &**d2s == ""); + println!("{}", std::borrow::Cow::Borrowed("") == ""); + let y = One; if y.len() == 0 { // No error; `One` does not have `.is_empty()`. @@ -226,3 +228,23 @@ fn binop_with_macros() { (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen.")); } + +fn no_infinite_recursion() -> bool { + struct S; + + impl Deref for S { + type Target = Self; + fn deref(&self) -> &Self::Target { + self + } + } + + impl PartialEq<&'static str> for S { + fn eq(&self, _other: &&'static str) -> bool { + false + } + } + + // Do not crash while checking if S implements `.is_empty()` + S == "" +} diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index 5c849a2aca646..8d6b57e4b6d4a 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -58,107 +58,113 @@ error: comparison to empty slice LL | println!("{}", &**d2s == ""); | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()` +error: comparison to empty slice + --> tests/ui/len_zero.rs:111:20 + | +LL | println!("{}", std::borrow::Cow::Borrowed("") == ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `std::borrow::Cow::Borrowed("").is_empty()` + error: length comparison to zero - --> tests/ui/len_zero.rs:124:8 + --> tests/ui/len_zero.rs:126:8 | LL | if has_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:127:8 + --> tests/ui/len_zero.rs:129:8 | LL | if has_is_empty.len() != 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:130:8 + --> tests/ui/len_zero.rs:132:8 | LL | if has_is_empty.len() > 0 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:133:8 + --> tests/ui/len_zero.rs:135:8 | LL | if has_is_empty.len() < 1 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:136:8 + --> tests/ui/len_zero.rs:138:8 | LL | if has_is_empty.len() >= 1 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:147:8 + --> tests/ui/len_zero.rs:149:8 | LL | if 0 == has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:150:8 + --> tests/ui/len_zero.rs:152:8 | LL | if 0 != has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:153:8 + --> tests/ui/len_zero.rs:155:8 | LL | if 0 < has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:156:8 + --> tests/ui/len_zero.rs:158:8 | LL | if 1 <= has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:159:8 + --> tests/ui/len_zero.rs:161:8 | LL | if 1 > has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:173:8 + --> tests/ui/len_zero.rs:175:8 | LL | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:185:6 + --> tests/ui/len_zero.rs:187:6 | LL | (has_is_empty.len() > 0).then(|| println!("This can happen.")); | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:186:6 + --> tests/ui/len_zero.rs:188:6 | LL | (has_is_empty.len() == 0).then(|| println!("Or this!")); | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:190:8 + --> tests/ui/len_zero.rs:192:8 | LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:224:8 + --> tests/ui/len_zero.rs:226:8 | LL | if has_is_empty.len() == compare_to!(0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:225:8 + --> tests/ui/len_zero.rs:227:8 | LL | if has_is_empty.len() == zero!() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:227:6 + --> tests/ui/len_zero.rs:229:6 | LL | (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen.")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors From 707653f268a2e8911751b738671bae8da9eb7225 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 18:47:23 +0100 Subject: [PATCH 036/189] Add lint for calling last() on DoubleEndedIterator --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/methods/double_ended_iterator_last.rs | 42 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 29 +++++++++++++ tests/ui/double_ended_iterator_last.fixed | 35 ++++++++++++++++ tests/ui/double_ended_iterator_last.rs | 35 ++++++++++++++++ tests/ui/double_ended_iterator_last.stderr | 17 ++++++++ 7 files changed, 160 insertions(+) create mode 100644 clippy_lints/src/methods/double_ended_iterator_last.rs create mode 100644 tests/ui/double_ended_iterator_last.fixed create mode 100644 tests/ui/double_ended_iterator_last.rs create mode 100644 tests/ui/double_ended_iterator_last.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 664a7e766304a..3e68b46cb0f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5493,6 +5493,7 @@ Released 2018-09-13 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons +[`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7451fb909ef84..3ff10d850f82b 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -372,6 +372,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::CLONE_ON_REF_PTR_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, crate::methods::CONST_IS_EMPTY_INFO, + crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO, crate::methods::DRAIN_COLLECT_INFO, crate::methods::ERR_EXPECT_INFO, crate::methods::EXPECT_FUN_CALL_INFO, diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs new file mode 100644 index 0000000000000..1322108e6feff --- /dev/null +++ b/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -0,0 +1,42 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::{Span, sym}; + +use super::DOUBLE_ENDED_ITERATOR_LAST; + +pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) { + let typeck = cx.typeck_results(); + + // Check if the current "last" method is that of the Iterator trait + if !is_trait_method(cx, expr, sym::Iterator) { + return; + } + + // Find id for DoubleEndedIterator trait + let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator) else { + return; + }; + + // Find the type of self + let self_type = typeck.expr_ty(self_expr).peel_refs(); + + // Check that the object implements the DoubleEndedIterator trait + if !implements_trait(cx, self_type, deiter_id, &[]) { + return; + } + + // Emit lint + span_lint_and_sugg( + cx, + DOUBLE_ENDED_ITERATOR_LAST, + call_span, + "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator", + "try", + "next_back()".to_string(), + Applicability::MachineApplicable, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 810287fa54167..51351f6b7cd1e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -14,6 +14,7 @@ mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; mod collapsible_str_replace; +mod double_ended_iterator_last; mod drain_collect; mod err_expect; mod expect_fun_call; @@ -4284,6 +4285,32 @@ declare_clippy_lint! { "map of a trivial closure (not dependent on parameter) over a range" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for `Iterator::last` being called on a `DoubleEndedIterator`, which can be replaced + /// with `DoubleEndedIterator::next_back`. + /// + /// ### Why is this bad? + /// + /// `Iterator::last` is implemented by consuming the iterator, which is unnecessary if + /// the iterator is a `DoubleEndedIterator`. Since Rust traits do not allow specialization, + /// `Iterator::last` cannot be optimized for `DoubleEndedIterator`. + /// + /// ### Example + /// ```no_run + /// let last_arg = "echo hello world".split(' ').last(); + /// ``` + /// Use instead: + /// ```no_run + /// let last_arg = "echo hello world".split(' ').next_back(); + /// ``` + #[clippy::version = "1.85.0"] + pub DOUBLE_ENDED_ITERATOR_LAST, + perf, + "using `Iterator::last` on a `DoubleEndedIterator`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4449,6 +4476,7 @@ impl_lint_pass!(Methods => [ MAP_ALL_ANY_IDENTITY, MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, UNNECESSARY_MAP_OR, + DOUBLE_ENDED_ITERATOR_LAST, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4931,6 +4959,7 @@ impl Methods { false, ); } + double_ended_iterator_last::check(cx, expr, recv, call_span); }, ("len", []) => { if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) { diff --git a/tests/ui/double_ended_iterator_last.fixed b/tests/ui/double_ended_iterator_last.fixed new file mode 100644 index 0000000000000..cfafd1045764b --- /dev/null +++ b/tests/ui/double_ended_iterator_last.fixed @@ -0,0 +1,35 @@ +#![warn(clippy::double_ended_iterator_last)] + +// Typical case +pub fn last_arg(s: &str) -> Option<&str> { + s.split(' ').next_back() +} + +fn main() { + // General case + struct DeIterator; + impl Iterator for DeIterator { + type Item = (); + fn next(&mut self) -> Option { + Some(()) + } + } + impl DoubleEndedIterator for DeIterator { + fn next_back(&mut self) -> Option { + Some(()) + } + } + let _ = DeIterator.next_back(); + // Should not apply to other methods of Iterator + let _ = DeIterator.count(); + + // Should not apply to simple iterators + struct SimpleIterator; + impl Iterator for SimpleIterator { + type Item = (); + fn next(&mut self) -> Option { + Some(()) + } + } + let _ = SimpleIterator.last(); +} diff --git a/tests/ui/double_ended_iterator_last.rs b/tests/ui/double_ended_iterator_last.rs new file mode 100644 index 0000000000000..ae80fb648389d --- /dev/null +++ b/tests/ui/double_ended_iterator_last.rs @@ -0,0 +1,35 @@ +#![warn(clippy::double_ended_iterator_last)] + +// Typical case +pub fn last_arg(s: &str) -> Option<&str> { + s.split(' ').last() +} + +fn main() { + // General case + struct DeIterator; + impl Iterator for DeIterator { + type Item = (); + fn next(&mut self) -> Option { + Some(()) + } + } + impl DoubleEndedIterator for DeIterator { + fn next_back(&mut self) -> Option { + Some(()) + } + } + let _ = DeIterator.last(); + // Should not apply to other methods of Iterator + let _ = DeIterator.count(); + + // Should not apply to simple iterators + struct SimpleIterator; + impl Iterator for SimpleIterator { + type Item = (); + fn next(&mut self) -> Option { + Some(()) + } + } + let _ = SimpleIterator.last(); +} diff --git a/tests/ui/double_ended_iterator_last.stderr b/tests/ui/double_ended_iterator_last.stderr new file mode 100644 index 0000000000000..b795c18a736ea --- /dev/null +++ b/tests/ui/double_ended_iterator_last.stderr @@ -0,0 +1,17 @@ +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:5:18 + | +LL | s.split(' ').last() + | ^^^^^^ help: try: `next_back()` + | + = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:22:24 + | +LL | let _ = DeIterator.last(); + | ^^^^^^ help: try: `next_back()` + +error: aborting due to 2 previous errors + From 458c955ae3a6f297510a86ab7efac4c7db5cc964 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 18:58:53 +0100 Subject: [PATCH 037/189] Fix conflicts with double_ended_iterator_last --- tests/ui/infinite_iter.rs | 2 +- tests/ui/iter_overeager_cloned.fixed | 7 ++++- tests/ui/iter_overeager_cloned.rs | 7 ++++- tests/ui/iter_overeager_cloned.stderr | 38 +++++++++++++-------------- tests/ui/starts_ends_with.fixed | 2 +- tests/ui/starts_ends_with.rs | 2 +- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index da95ba04b821b..178e300ff5bf4 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,4 +1,4 @@ -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::double_ended_iterator_last)] use std::iter::repeat; fn square_is_lower_64(x: &u32) -> bool { diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index 7d8a584b0224c..d7d3d299349ee 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -1,5 +1,10 @@ #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] -#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)] +#![allow( + dead_code, + clippy::let_unit_value, + clippy::useless_vec, + clippy::double_ended_iterator_last +)] fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 58c374ab8cd10..45e1349febd06 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -1,5 +1,10 @@ #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] -#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)] +#![allow( + dead_code, + clippy::let_unit_value, + clippy::useless_vec, + clippy::double_ended_iterator_last +)] fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index 7a822a79494b7..e6680266f1076 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -1,5 +1,5 @@ error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:7:29 + --> tests/ui/iter_overeager_cloned.rs:12:29 | LL | let _: Option = vec.iter().cloned().last(); | ^^^^^^^^^^---------------- @@ -10,7 +10,7 @@ LL | let _: Option = vec.iter().cloned().last(); = help: to override `-D warnings` add `#[allow(clippy::iter_overeager_cloned)]` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:9:29 + --> tests/ui/iter_overeager_cloned.rs:14:29 | LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- @@ -18,7 +18,7 @@ LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); | help: try: `.next().cloned()` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:11:20 + --> tests/ui/iter_overeager_cloned.rs:16:20 | LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------- @@ -29,7 +29,7 @@ LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:13:21 + --> tests/ui/iter_overeager_cloned.rs:18:21 | LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); | ^^^^^^^^^^----------------- @@ -37,7 +37,7 @@ LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); | help: try: `.take(2).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:15:21 + --> tests/ui/iter_overeager_cloned.rs:20:21 | LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); | ^^^^^^^^^^----------------- @@ -45,7 +45,7 @@ LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); | help: try: `.skip(2).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:17:13 + --> tests/ui/iter_overeager_cloned.rs:22:13 | LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- @@ -53,7 +53,7 @@ LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | help: try: `.nth(2).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:19:13 + --> tests/ui/iter_overeager_cloned.rs:24:13 | LL | let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] | _____________^ @@ -69,7 +69,7 @@ LL ~ .flatten().cloned(); | error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:24:13 + --> tests/ui/iter_overeager_cloned.rs:29:13 | LL | let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); | ^^^^^^^^^^---------------------------------------- @@ -77,7 +77,7 @@ LL | let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); | help: try: `.filter(|&x| x.starts_with('2')).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:26:13 + --> tests/ui/iter_overeager_cloned.rs:31:13 | LL | let _ = vec.iter().cloned().find(|x| x == "2"); | ^^^^^^^^^^---------------------------- @@ -85,7 +85,7 @@ LL | let _ = vec.iter().cloned().find(|x| x == "2"); | help: try: `.find(|&x| x == "2").cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:30:17 + --> tests/ui/iter_overeager_cloned.rs:35:17 | LL | let _ = vec.iter().cloned().filter(f); | ^^^^^^^^^^------------------- @@ -93,7 +93,7 @@ LL | let _ = vec.iter().cloned().filter(f); | help: try: `.filter(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:31:17 + --> tests/ui/iter_overeager_cloned.rs:36:17 | LL | let _ = vec.iter().cloned().find(f); | ^^^^^^^^^^----------------- @@ -101,7 +101,7 @@ LL | let _ = vec.iter().cloned().find(f); | help: try: `.find(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:37:17 + --> tests/ui/iter_overeager_cloned.rs:42:17 | LL | let _ = vec.iter().cloned().filter(f); | ^^^^^^^^^^------------------- @@ -109,7 +109,7 @@ LL | let _ = vec.iter().cloned().filter(f); | help: try: `.filter(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:38:17 + --> tests/ui/iter_overeager_cloned.rs:43:17 | LL | let _ = vec.iter().cloned().find(f); | ^^^^^^^^^^----------------- @@ -117,7 +117,7 @@ LL | let _ = vec.iter().cloned().find(f); | help: try: `.find(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:45:9 + --> tests/ui/iter_overeager_cloned.rs:50:9 | LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) | ^^^^------------------------------------------------------- @@ -125,7 +125,7 @@ LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) | help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:56:13 + --> tests/ui/iter_overeager_cloned.rs:61:13 | LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) | ^^^^------------------------------------------------------------ @@ -133,7 +133,7 @@ LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target | help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:60:13 + --> tests/ui/iter_overeager_cloned.rs:65:13 | LL | let _ = vec.iter().cloned().map(|x| x.len()); | ^^^^^^^^^^-------------------------- @@ -141,7 +141,7 @@ LL | let _ = vec.iter().cloned().map(|x| x.len()); | help: try: `.map(|x| x.len())` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:65:13 + --> tests/ui/iter_overeager_cloned.rs:70:13 | LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); | ^^^^^^^^^^---------------------------------------------- @@ -149,7 +149,7 @@ LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); | help: try: `.for_each(|x| assert!(!x.is_empty()))` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:67:13 + --> tests/ui/iter_overeager_cloned.rs:72:13 | LL | let _ = vec.iter().cloned().all(|x| x.len() == 1); | ^^^^^^^^^^------------------------------- @@ -157,7 +157,7 @@ LL | let _ = vec.iter().cloned().all(|x| x.len() == 1); | help: try: `.all(|x| x.len() == 1)` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:69:13 + --> tests/ui/iter_overeager_cloned.rs:74:13 | LL | let _ = vec.iter().cloned().any(|x| x.len() == 1); | ^^^^^^^^^^------------------------------- diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed index 4a66ca7ec91a1..252b6e5a98c09 100644 --- a/tests/ui/starts_ends_with.fixed +++ b/tests/ui/starts_ends_with.fixed @@ -1,4 +1,4 @@ -#![allow(clippy::needless_if, dead_code, unused_must_use)] +#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)] fn main() {} diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index 16a68e02d66d3..6c5655f31782d 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -1,4 +1,4 @@ -#![allow(clippy::needless_if, dead_code, unused_must_use)] +#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)] fn main() {} From 09c5d34f98f53d4f0b4181404608d4c1bcede4d5 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 19:43:27 +0100 Subject: [PATCH 038/189] Dogfood double_ended_iterator_last --- clippy_lints/src/attrs/mixed_attributes_style.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/doc/empty_line_after.rs | 2 +- clippy_lints/src/doc/markdown.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/returns.rs | 4 ++-- clippy_lints/src/unit_types/unit_arg.rs | 2 +- clippy_lints/src/vec.rs | 2 +- clippy_utils/src/msrvs.rs | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/attrs/mixed_attributes_style.rs b/clippy_lints/src/attrs/mixed_attributes_style.rs index 32c28c09c3602..8c91c65eaf76b 100644 --- a/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute]) fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); - let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { + let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) { first.span.with_hi(last.span.hi()) } else { return; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index e73bfc6ebf7a1..6122fcb28da52 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -110,7 +110,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: // Prevent "elseif" // Check that the "else" is followed by whitespace let up_to_else = then_span.between(block.span); - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { + let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().next_back() { !c.is_whitespace() } else { false diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs index 099194d4e7467..74058c2fbf58b 100644 --- a/clippy_lints/src/doc/empty_line_after.rs +++ b/clippy_lints/src/doc/empty_line_after.rs @@ -227,7 +227,7 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { span_lint_and_then( cx, lint, - first_gap.prev_stop.span.to(empty_lines().last().unwrap()), + first_gap.prev_stop.span.to(empty_lines().next_back().unwrap()), format!("empty {lines} after {kind_desc}"), |diag| { if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() { diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index 8cdaba88e5095..0c8e50445d655 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -89,7 +89,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b let s = if let Some(prefix) = s.strip_suffix("es") && prefix.chars().all(|c| c.is_ascii_uppercase()) - && matches!(prefix.chars().last(), Some('S' | 'X')) + && matches!(prefix.chars().next_back(), Some('S' | 'X')) { prefix } else if let Some(prefix) = s.strip_suffix("ified") diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 5db28e9ae9b84..502e6f3a08d04 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -149,7 +149,7 @@ fn check_assign<'tcx>( block: &'tcx hir::Block<'_>, ) -> Option<&'tcx hir::Expr<'tcx>> { if block.expr.is_none() - && let Some(expr) = block.stmts.iter().last() + && let Some(expr) = block.stmts.iter().next_back() && let hir::StmtKind::Semi(expr) = expr.kind && let hir::ExprKind::Assign(var, value, _) = expr.kind && path_to_local_id(var, decl) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index aeff31d02d26f..5ed6e3fead5f0 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { // we need both a let-binding stmt and an expr if let Some(retexpr) = block.expr - && let Some(stmt) = block.stmts.iter().last() + && let Some(stmt) = block.stmts.iter().next_back() && let StmtKind::Let(local) = &stmt.kind && local.ty.is_none() && cx.tcx.hir().attrs(local.hir_id).is_empty() @@ -315,7 +315,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, if let ExprKind::Block(block, _) = expr_kind { if let Some(block_expr) = block.expr { check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None); - } else if let Some(stmt) = block.stmts.iter().last() { + } else if let Some(stmt) = block.stmts.iter().next_back() { match stmt.kind { StmtKind::Expr(expr) => { check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None); diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 47d6fe7db7667..5e49eae140468 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -78,7 +78,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp .filter_map(|arg| { if let ExprKind::Block(block, _) = arg.kind && block.expr.is_none() - && let Some(last_stmt) = block.stmts.iter().last() + && let Some(last_stmt) = block.stmts.iter().next_back() && let StmtKind::Semi(last_expr) = last_stmt.kind && let Some(snip) = last_expr.span.get_source_text(cx) { diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index ef1c46154d29a..2c7e0fea17d7f 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -175,7 +175,7 @@ impl UselessVec { } }, higher::VecArgs::Vec(args) => { - let args_span = if let Some(last) = args.iter().last() { + let args_span = if let Some(last) = args.iter().next_back() { if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack { return; } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 98bcedecccc65..2169a5fdd63ba 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -130,7 +130,7 @@ impl Msrv { let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); if let Some(msrv_attr) = msrv_attrs.next() { - if let Some(duplicate) = msrv_attrs.last() { + if let Some(duplicate) = msrv_attrs.next_back() { sess.dcx() .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") .with_span_note(msrv_attr.span(), "first definition found here") From 27acfd8a5b9dd1eb91e044e07201b4a9044a2bbd Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 20:33:58 +0100 Subject: [PATCH 039/189] Prefer if chain to let-else --- .../src/methods/double_ended_iterator_last.rs | 42 ++++++------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs index 1322108e6feff..dec59b1c34efa 100644 --- a/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -9,34 +9,18 @@ use rustc_span::{Span, sym}; use super::DOUBLE_ENDED_ITERATOR_LAST; pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) { - let typeck = cx.typeck_results(); - - // Check if the current "last" method is that of the Iterator trait - if !is_trait_method(cx, expr, sym::Iterator) { - return; - } - - // Find id for DoubleEndedIterator trait - let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator) else { - return; - }; - - // Find the type of self - let self_type = typeck.expr_ty(self_expr).peel_refs(); - - // Check that the object implements the DoubleEndedIterator trait - if !implements_trait(cx, self_type, deiter_id, &[]) { - return; + if is_trait_method(cx, expr, sym::Iterator) + && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator) + && implements_trait(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), deiter_id, &[]) + { + span_lint_and_sugg( + cx, + DOUBLE_ENDED_ITERATOR_LAST, + call_span, + "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator", + "try", + "next_back()".to_string(), + Applicability::MachineApplicable, + ); } - - // Emit lint - span_lint_and_sugg( - cx, - DOUBLE_ENDED_ITERATOR_LAST, - call_span, - "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator", - "try", - "next_back()".to_string(), - Applicability::MachineApplicable, - ); } From 2a2e87b398c677062280254f6c5db8757e4b7ce3 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 1 Jan 2025 18:51:39 +0100 Subject: [PATCH 040/189] Rename the internal simpler `quote` macro to `minimal_quote` --- library/proc_macro/src/quote.rs | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs index 04fa696d5e6be..6faa41b297005 100644 --- a/library/proc_macro/src/quote.rs +++ b/library/proc_macro/src/quote.rs @@ -6,10 +6,10 @@ use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; +macro_rules! minimal_quote_tt { + (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) }; + ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, minimal_quote!($($t)*)) }; + ({$($t:tt)*}) => { Group::new(Delimiter::Brace, minimal_quote!($($t)*)) }; (,) => { Punct::new(',', Spacing::Alone) }; (.) => { Punct::new('.', Spacing::Alone) }; (;) => { Punct::new(';', Spacing::Alone) }; @@ -21,7 +21,7 @@ macro_rules! quote_tt { ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; } -macro_rules! quote_ts { +macro_rules! minimal_quote_ts { ((@ $($t:tt)*)) => { $($t)* }; (::) => { [ @@ -35,7 +35,7 @@ macro_rules! quote_ts { }) .collect::() }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; + ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) }; } /// Simpler version of the real `quote!` macro, implemented solely @@ -46,11 +46,11 @@ macro_rules! quote_ts { /// /// Note: supported tokens are a subset of the real `quote!`, but /// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { +macro_rules! minimal_quote { () => { TokenStream::new() }; ($($t:tt)*) => { [ - $(TokenStream::from(quote_ts!($t)),)* + $(TokenStream::from(minimal_quote_ts!($t)),)* ].iter().cloned().collect::() }; } @@ -62,9 +62,9 @@ macro_rules! quote { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote(stream: TokenStream) -> TokenStream { if stream.is_empty() { - return quote!(crate::TokenStream::new()); + return minimal_quote!(crate::TokenStream::new()); } - let proc_macro_crate = quote!(crate); + let proc_macro_crate = minimal_quote!(crate); let mut after_dollar = false; let tokens = stream .into_iter() @@ -73,7 +73,7 @@ pub fn quote(stream: TokenStream) -> TokenStream { after_dollar = false; match tree { TokenTree::Ident(_) => { - return Some(quote!(Into::::into( + return Some(minimal_quote!(Into::::into( Clone::clone(&(@ tree))),)); } TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} @@ -86,28 +86,28 @@ pub fn quote(stream: TokenStream) -> TokenStream { } } - Some(quote!(crate::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new( + Some(minimal_quote!(crate::TokenStream::from((@ match tree { + TokenTree::Punct(tt) => minimal_quote!(crate::TokenTree::Punct(crate::Punct::new( (@ TokenTree::from(Literal::character(tt.as_char()))), (@ match tt.spacing() { - Spacing::Alone => quote!(crate::Spacing::Alone), - Spacing::Joint => quote!(crate::Spacing::Joint), + Spacing::Alone => minimal_quote!(crate::Spacing::Alone), + Spacing::Joint => minimal_quote!(crate::Spacing::Joint), }), ))), - TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new( + TokenTree::Group(tt) => minimal_quote!(crate::TokenTree::Group(crate::Group::new( (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis), - Delimiter::Brace => quote!(crate::Delimiter::Brace), - Delimiter::Bracket => quote!(crate::Delimiter::Bracket), - Delimiter::None => quote!(crate::Delimiter::None), + Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis), + Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace), + Delimiter::Bracket => minimal_quote!(crate::Delimiter::Bracket), + Delimiter::None => minimal_quote!(crate::Delimiter::None), }), (@ quote(tt.stream())), ))), - TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new( + TokenTree::Ident(tt) => minimal_quote!(crate::TokenTree::Ident(crate::Ident::new( (@ TokenTree::from(Literal::string(&tt.to_string()))), (@ quote_span(proc_macro_crate.clone(), tt.span())), ))), - TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({ + TokenTree::Literal(tt) => minimal_quote!(crate::TokenTree::Literal({ let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) .parse::() .unwrap() @@ -129,7 +129,7 @@ pub fn quote(stream: TokenStream) -> TokenStream { panic!("unexpected trailing `$` in `quote!`"); } - quote!([(@ tokens)].iter().cloned().collect::()) + minimal_quote!([(@ tokens)].iter().cloned().collect::()) } /// Quote a `Span` into a `TokenStream`. @@ -137,5 +137,5 @@ pub fn quote(stream: TokenStream) -> TokenStream { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) + minimal_quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) } From 7331cc0f81d97fbc4f4eb47890cb10fe7c275696 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 22:14:17 +0100 Subject: [PATCH 041/189] Only complain about default Iterator::last() --- .../src/methods/double_ended_iterator_last.rs | 17 ++++++++++++++++- tests/ui/double_ended_iterator_last.fixed | 18 ++++++++++++++++++ tests/ui/double_ended_iterator_last.rs | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs index dec59b1c34efa..118ab7cd93b0a 100644 --- a/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -4,14 +4,29 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; +use rustc_middle::ty::Instance; use rustc_span::{Span, sym}; use super::DOUBLE_ENDED_ITERATOR_LAST; pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) { + let typeck = cx.typeck_results(); + + // if the "last" method is that of Iterator if is_trait_method(cx, expr, sym::Iterator) + // if self implements DoubleEndedIterator && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator) - && implements_trait(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), deiter_id, &[]) + && let self_type = cx.typeck_results().expr_ty(self_expr) + && implements_trait(cx, self_type.peel_refs(), deiter_id, &[]) + // resolve the method definition + && let id = typeck.type_dependent_def_id(expr.hir_id).unwrap() + && let args = typeck.node_args(expr.hir_id) + && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) + // find the provided definition of Iterator::last + && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name == sym!(last)) + // if the resolved method is the same as the provided definition + && fn_def.def_id() == last_def.def_id { span_lint_and_sugg( cx, diff --git a/tests/ui/double_ended_iterator_last.fixed b/tests/ui/double_ended_iterator_last.fixed index cfafd1045764b..06c48e337537c 100644 --- a/tests/ui/double_ended_iterator_last.fixed +++ b/tests/ui/double_ended_iterator_last.fixed @@ -32,4 +32,22 @@ fn main() { } } let _ = SimpleIterator.last(); + + // Should not apply to custom implementations of last() + struct CustomLast; + impl Iterator for CustomLast { + type Item = (); + fn next(&mut self) -> Option { + Some(()) + } + fn last(self) -> Option { + Some(()) + } + } + impl DoubleEndedIterator for CustomLast { + fn next_back(&mut self) -> Option { + Some(()) + } + } + let _ = CustomLast.last(); } diff --git a/tests/ui/double_ended_iterator_last.rs b/tests/ui/double_ended_iterator_last.rs index ae80fb648389d..9c13b496d117e 100644 --- a/tests/ui/double_ended_iterator_last.rs +++ b/tests/ui/double_ended_iterator_last.rs @@ -32,4 +32,22 @@ fn main() { } } let _ = SimpleIterator.last(); + + // Should not apply to custom implementations of last() + struct CustomLast; + impl Iterator for CustomLast { + type Item = (); + fn next(&mut self) -> Option { + Some(()) + } + fn last(self) -> Option { + Some(()) + } + } + impl DoubleEndedIterator for CustomLast { + fn next_back(&mut self) -> Option { + Some(()) + } + } + let _ = CustomLast.last(); } From 0d213aa09aa263474d52fce5bcab9d3f662f7d72 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 22:16:33 +0100 Subject: [PATCH 042/189] Revert "Dogfood double_ended_iterator_last" This reverts commit 09c5d34f98f53d4f0b4181404608d4c1bcede4d5. --- clippy_lints/src/attrs/mixed_attributes_style.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/doc/empty_line_after.rs | 2 +- clippy_lints/src/doc/markdown.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/returns.rs | 4 ++-- clippy_lints/src/unit_types/unit_arg.rs | 2 +- clippy_lints/src/vec.rs | 2 +- clippy_utils/src/msrvs.rs | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/attrs/mixed_attributes_style.rs b/clippy_lints/src/attrs/mixed_attributes_style.rs index 8c91c65eaf76b..32c28c09c3602 100644 --- a/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute]) fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); - let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) { + let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { first.span.with_hi(last.span.hi()) } else { return; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 6122fcb28da52..e73bfc6ebf7a1 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -110,7 +110,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: // Prevent "elseif" // Check that the "else" is followed by whitespace let up_to_else = then_span.between(block.span); - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().next_back() { + let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs index 74058c2fbf58b..099194d4e7467 100644 --- a/clippy_lints/src/doc/empty_line_after.rs +++ b/clippy_lints/src/doc/empty_line_after.rs @@ -227,7 +227,7 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { span_lint_and_then( cx, lint, - first_gap.prev_stop.span.to(empty_lines().next_back().unwrap()), + first_gap.prev_stop.span.to(empty_lines().last().unwrap()), format!("empty {lines} after {kind_desc}"), |diag| { if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() { diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index 0c8e50445d655..8cdaba88e5095 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -89,7 +89,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b let s = if let Some(prefix) = s.strip_suffix("es") && prefix.chars().all(|c| c.is_ascii_uppercase()) - && matches!(prefix.chars().next_back(), Some('S' | 'X')) + && matches!(prefix.chars().last(), Some('S' | 'X')) { prefix } else if let Some(prefix) = s.strip_suffix("ified") diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 502e6f3a08d04..5db28e9ae9b84 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -149,7 +149,7 @@ fn check_assign<'tcx>( block: &'tcx hir::Block<'_>, ) -> Option<&'tcx hir::Expr<'tcx>> { if block.expr.is_none() - && let Some(expr) = block.stmts.iter().next_back() + && let Some(expr) = block.stmts.iter().last() && let hir::StmtKind::Semi(expr) = expr.kind && let hir::ExprKind::Assign(var, value, _) = expr.kind && path_to_local_id(var, decl) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 5ed6e3fead5f0..aeff31d02d26f 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { // we need both a let-binding stmt and an expr if let Some(retexpr) = block.expr - && let Some(stmt) = block.stmts.iter().next_back() + && let Some(stmt) = block.stmts.iter().last() && let StmtKind::Let(local) = &stmt.kind && local.ty.is_none() && cx.tcx.hir().attrs(local.hir_id).is_empty() @@ -315,7 +315,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, if let ExprKind::Block(block, _) = expr_kind { if let Some(block_expr) = block.expr { check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None); - } else if let Some(stmt) = block.stmts.iter().next_back() { + } else if let Some(stmt) = block.stmts.iter().last() { match stmt.kind { StmtKind::Expr(expr) => { check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None); diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 5e49eae140468..47d6fe7db7667 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -78,7 +78,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp .filter_map(|arg| { if let ExprKind::Block(block, _) = arg.kind && block.expr.is_none() - && let Some(last_stmt) = block.stmts.iter().next_back() + && let Some(last_stmt) = block.stmts.iter().last() && let StmtKind::Semi(last_expr) = last_stmt.kind && let Some(snip) = last_expr.span.get_source_text(cx) { diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 2c7e0fea17d7f..ef1c46154d29a 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -175,7 +175,7 @@ impl UselessVec { } }, higher::VecArgs::Vec(args) => { - let args_span = if let Some(last) = args.iter().next_back() { + let args_span = if let Some(last) = args.iter().last() { if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack { return; } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 2169a5fdd63ba..98bcedecccc65 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -130,7 +130,7 @@ impl Msrv { let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); if let Some(msrv_attr) = msrv_attrs.next() { - if let Some(duplicate) = msrv_attrs.next_back() { + if let Some(duplicate) = msrv_attrs.last() { sess.dcx() .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") .with_span_note(msrv_attr.span(), "first definition found here") From d67c00f7232b104817cd30f76ad7089a3be5a389 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 22:18:08 +0100 Subject: [PATCH 043/189] Dogfood double_ended_iterator_last --- clippy_lints/src/attrs/mixed_attributes_style.rs | 2 +- clippy_lints/src/methods/double_ended_iterator_last.rs | 2 +- clippy_utils/src/msrvs.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/attrs/mixed_attributes_style.rs b/clippy_lints/src/attrs/mixed_attributes_style.rs index 32c28c09c3602..8c91c65eaf76b 100644 --- a/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute]) fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); - let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { + let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) { first.span.with_hi(last.span.hi()) } else { return; diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs index 118ab7cd93b0a..208172980c9f5 100644 --- a/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name == sym!(last)) + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last") // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id { diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 98bcedecccc65..2169a5fdd63ba 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -130,7 +130,7 @@ impl Msrv { let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); if let Some(msrv_attr) = msrv_attrs.next() { - if let Some(duplicate) = msrv_attrs.last() { + if let Some(duplicate) = msrv_attrs.next_back() { sess.dcx() .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") .with_span_note(msrv_attr.span(), "first definition found here") From f18399fb69a07571f9a95732be5f6ec6b7517a78 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sat, 28 Dec 2024 09:50:52 -0700 Subject: [PATCH 044/189] Emit redundant if when duplicated in `needless_continue` --- clippy_lints/src/needless_continue.rs | 29 +++++++++++++----- tests/ui/needless_continue.rs | 26 ++++++++++++++++ tests/ui/needless_continue.stderr | 44 ++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index dd75e0f4e4bf2..05b31fc84b9b2 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -78,14 +78,16 @@ declare_clippy_lint! { /// ``` /// /// ```rust - /// fn foo() -> std::io::ErrorKind { std::io::ErrorKind::NotFound } + /// # use std::io::ErrorKind; + /// + /// fn foo() -> ErrorKind { ErrorKind::NotFound } /// for _ in 0..10 { /// match foo() { - /// std::io::ErrorKind::NotFound => { + /// ErrorKind::NotFound => { /// eprintln!("not found"); /// continue /// } - /// std::io::ErrorKind::TimedOut => { + /// ErrorKind::TimedOut => { /// eprintln!("timeout"); /// continue /// } @@ -100,13 +102,15 @@ declare_clippy_lint! { /// /// /// ```rust - /// fn foo() -> std::io::ErrorKind { std::io::ErrorKind::NotFound } + /// # use std::io::ErrorKind; + /// + /// fn foo() -> ErrorKind { ErrorKind::NotFound } /// for _ in 0..10 { /// match foo() { - /// std::io::ErrorKind::NotFound => { + /// ErrorKind::NotFound => { /// eprintln!("not found"); /// } - /// std::io::ErrorKind::TimedOut => { + /// ErrorKind::TimedOut => { /// eprintln!("timeout"); /// } /// _ => { @@ -422,9 +426,10 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { ); } }; - check_last_stmt_in_block(loop_block, &p); - for (i, stmt) in loop_block.stmts.iter().enumerate() { + let stmts = &loop_block.stmts; + for (i, stmt) in stmts.iter().enumerate() { + let mut maybe_emitted_in_if = false; with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { let data = &LintData { if_expr, @@ -434,6 +439,8 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { stmt_idx: i, loop_block, }; + + maybe_emitted_in_if = true; if needless_continue_in_else(else_expr, label) { emit_warning( cx, @@ -443,8 +450,14 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { ); } else if is_first_block_stmt_continue(then_block, label) { emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock); + } else { + maybe_emitted_in_if = false; } }); + + if i == stmts.len() - 1 && !maybe_emitted_in_if { + check_last_stmt_in_block(loop_block, &p); + } } }); } diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index bc7233f3ba506..334a2b32775f3 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -194,6 +194,32 @@ mod issue_4077 { } } } + + for _ in 0..10 { + match "foo".parse::() { + Ok(_) => do_something(), + Err(_) => { + println!("bar-10"); + continue; + }, + } + } + + loop { + if true { + } else { + // redundant `else` + continue; // redundant `continue` + } + } + + loop { + if some_expr() { + continue; + } else { + do_something(); + } + } } // The contents of these functions are irrelevant, the purpose of this file is diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index 4ab443108b0fa..ec39d62341957 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -168,5 +168,47 @@ LL | continue 'inner; | = help: consider dropping the `continue` expression -error: aborting due to 12 previous errors +error: this `continue` expression is redundant + --> tests/ui/needless_continue.rs:203:21 + | +LL | continue; + | ^^^^^^^^ + | + = help: consider dropping the `continue` expression + +error: this `else` block is redundant + --> tests/ui/needless_continue.rs:210:20 + | +LL | } else { + | ____________________^ +LL | | // redundant `else` +LL | | continue; // redundant `continue` +LL | | } + | |_____________^ + | + = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block + if true { + // merged code follows: + + } + +error: there is no need for an explicit `else` block for this `if` expression + --> tests/ui/needless_continue.rs:217:13 + | +LL | / if some_expr() { +LL | | continue; +LL | | } else { +LL | | do_something(); +LL | | } + | |_____________^ + | + = help: consider dropping the `else` clause + if some_expr() { + continue; + } + { + do_something(); + } + +error: aborting due to 15 previous errors From 3af8dc4744fc0ccc4b895e6ae1ff8f464d9a6c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:42:45 +0800 Subject: [PATCH 045/189] triagebot: register `relnotes-interest-group` ping group --- triagebot.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 5660eb999b789..e9ebb6b52189d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -172,6 +172,12 @@ issues). """ label = "O-emscripten" +[ping.relnotes-interest-group] +message = """\ +Hi relnotes-interest-group, this PR adds release notes. Could you review this PR +if you have time? Thanks <3 +""" + [prioritize] label = "I-prioritize" From 9c46e1173f9bb6dbf1cd2bded405d90771b28471 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 2 Jan 2025 23:53:24 +0100 Subject: [PATCH 046/189] Remove unneeded parentheses in `unnecessary_map_or` lint output When the expression is transformed into an equality, parentheses are needed only if the resulting equality is used: - as a receiver in a method call - as part of a binary or unary expression - as part of a cast In other cases, which will be the majority, no parentheses are required. This makes the lint suggestions cleaner. --- .../src/methods/unnecessary_map_or.rs | 24 +++++-- tests/ui/unnecessary_map_or.fixed | 14 ++-- tests/ui/unnecessary_map_or.rs | 4 ++ tests/ui/unnecessary_map_or.stderr | 66 ++++++++++++------- 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index 1199d28976107..b7dbebe60a42e 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -7,7 +7,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; use clippy_utils::visitors::is_local_used; -use clippy_utils::{is_from_proc_macro, path_to_local_id}; +use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id}; use rustc_ast::LitKind::Bool; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; @@ -96,11 +96,25 @@ pub(super) fn check<'a>( Sugg::hir(cx, non_binding_location, "") ))); - let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding) - .maybe_par() - .into_string(); + let mut app = Applicability::MachineApplicable; + let binop = make_binop( + op.node, + &Sugg::hir_with_applicability(cx, recv, "..", &mut app), + &inner_non_binding, + ); - (binop, "a standard comparison", Applicability::MaybeIncorrect) + let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) { + match parent_expr.kind { + ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_par(), + ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_par(), + _ => binop, + } + } else { + binop + } + .into_string(); + + (sugg, "a standard comparison", app) } else if !def_bool && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed index 70b78ceca502f..efea28e7045c8 100644 --- a/tests/ui/unnecessary_map_or.fixed +++ b/tests/ui/unnecessary_map_or.fixed @@ -3,15 +3,16 @@ #![allow(clippy::no_effect)] #![allow(clippy::eq_op)] #![allow(clippy::unnecessary_lazy_evaluations)] +#![allow(clippy::nonminimal_bool)] #[clippy::msrv = "1.70.0"] #[macro_use] extern crate proc_macros; fn main() { // should trigger - let _ = (Some(5) == Some(5)); - let _ = (Some(5) != Some(5)); - let _ = (Some(5) == Some(5)); + let _ = Some(5) == Some(5); + let _ = Some(5) != Some(5); + let _ = Some(5) == Some(5); let _ = Some(5).is_some_and(|n| { let _ = n; 6 >= 5 @@ -21,10 +22,13 @@ fn main() { let _ = Some(5).is_some_and(|n| n == n); let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); - let _ = (Ok::(5) == Ok(5)); + let _ = Ok::(5) == Ok(5); let _ = (Some(5) == Some(5)).then(|| 1); let _ = Some(5).is_none_or(|n| n == 5); let _ = Some(5).is_none_or(|n| 5 == n); + let _ = !(Some(5) == Some(5)); + let _ = (Some(5) == Some(5)) || false; + let _ = (Some(5) == Some(5)) as usize; macro_rules! x { () => { @@ -60,7 +64,7 @@ fn main() { #[derive(PartialEq)] struct S2; let r: Result = Ok(4); - let _ = (r == Ok(8)); + let _ = r == Ok(8); // do not lint `Result::map_or(true, …)` let r: Result = Ok(4); diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs index 5075771597719..05a0ca816ef6d 100644 --- a/tests/ui/unnecessary_map_or.rs +++ b/tests/ui/unnecessary_map_or.rs @@ -3,6 +3,7 @@ #![allow(clippy::no_effect)] #![allow(clippy::eq_op)] #![allow(clippy::unnecessary_lazy_evaluations)] +#![allow(clippy::nonminimal_bool)] #[clippy::msrv = "1.70.0"] #[macro_use] extern crate proc_macros; @@ -28,6 +29,9 @@ fn main() { let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); let _ = Some(5).map_or(true, |n| n == 5); let _ = Some(5).map_or(true, |n| 5 == n); + let _ = !Some(5).map_or(false, |n| n == 5); + let _ = Some(5).map_or(false, |n| n == 5) || false; + let _ = Some(5).map_or(false, |n| n == 5) as usize; macro_rules! x { () => { diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr index 890abb0122885..2b78996d5f3e3 100644 --- a/tests/ui/unnecessary_map_or.stderr +++ b/tests/ui/unnecessary_map_or.stderr @@ -1,30 +1,30 @@ error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:12:13 + --> tests/ui/unnecessary_map_or.rs:13:13 | LL | let _ = Some(5).map_or(false, |n| n == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) == Some(5)` | = note: `-D clippy::unnecessary-map-or` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:13:13 + --> tests/ui/unnecessary_map_or.rs:14:13 | LL | let _ = Some(5).map_or(true, |n| n != 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) != Some(5)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:14:13 + --> tests/ui/unnecessary_map_or.rs:15:13 | LL | let _ = Some(5).map_or(false, |n| { | _____________^ LL | | let _ = 1; LL | | n == 5 LL | | }); - | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | |______^ help: use a standard comparison instead: `Some(5) == Some(5)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:18:13 + --> tests/ui/unnecessary_map_or.rs:19:13 | LL | let _ = Some(5).map_or(false, |n| { | _____________^ @@ -42,88 +42,106 @@ LL ~ }); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:22:13 + --> tests/ui/unnecessary_map_or.rs:23:13 | LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:23:13 + --> tests/ui/unnecessary_map_or.rs:24:13 | LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:24:13 + --> tests/ui/unnecessary_map_or.rs:25:13 | LL | let _ = Some(5).map_or(false, |n| n == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:25:13 + --> tests/ui/unnecessary_map_or.rs:26:13 | LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:26:13 + --> tests/ui/unnecessary_map_or.rs:27:13 | LL | let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::, i32>(vec![5]).is_ok_and(|n| n == [5])` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:27:13 + --> tests/ui/unnecessary_map_or.rs:28:13 | LL | let _ = Ok::(5).map_or(false, |n| n == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::(5) == Ok(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Ok::(5) == Ok(5)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:28:13 + --> tests/ui/unnecessary_map_or.rs:29:13 | LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:29:13 + --> tests/ui/unnecessary_map_or.rs:30:13 | LL | let _ = Some(5).map_or(true, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:30:13 + --> tests/ui/unnecessary_map_or.rs:31:13 | LL | let _ = Some(5).map_or(true, |n| 5 == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:54:13 + --> tests/ui/unnecessary_map_or.rs:32:14 + | +LL | let _ = !Some(5).map_or(false, |n| n == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:33:13 + | +LL | let _ = Some(5).map_or(false, |n| n == 5) || false; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:34:13 + | +LL | let _ = Some(5).map_or(false, |n| n == 5) as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:58:13 | LL | let _ = r.map_or(false, |x| x == 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:59:13 + --> tests/ui/unnecessary_map_or.rs:63:13 | LL | let _ = r.map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:60:13 + --> tests/ui/unnecessary_map_or.rs:64:13 | LL | let _ = Some(5).map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:61:13 + --> tests/ui/unnecessary_map_or.rs:65:13 | LL | let _ = Some(5).map_or(true, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)` error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:66:13 + --> tests/ui/unnecessary_map_or.rs:70:13 | LL | let _ = r.map_or(false, |x| x == 8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `r == Ok(8)` -error: aborting due to 18 previous errors +error: aborting due to 21 previous errors From 7ac151508e6026945e6fdf0e3c5338efca534535 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 2 Jan 2025 23:28:08 +0100 Subject: [PATCH 047/189] Make CI a little bit safer --- .github/workflows/clippy_dev.yml | 3 +++ .github/workflows/clippy_mq.yml | 10 ++++++++++ .github/workflows/clippy_pr.yml | 3 +++ .github/workflows/deploy.yml | 10 +++++++++- .github/workflows/lintcheck.yml | 8 ++++++++ .github/workflows/remark.yml | 3 +++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index bcb3193ad6708..d6534fbaff946 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -17,6 +17,9 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false # Run - name: Build diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml index 496220480508b..078a278e21a89 100644 --- a/.github/workflows/clippy_mq.yml +++ b/.github/workflows/clippy_mq.yml @@ -23,6 +23,8 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.ref }} + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false # Run - name: Check Changelog @@ -63,6 +65,8 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + persist-credentials: false - name: Install i686 dependencies if: matrix.host == 'i686-unknown-linux-gnu' @@ -121,6 +125,8 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + persist-credentials: false - name: Install toolchain run: rustup show active-toolchain @@ -136,6 +142,8 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + persist-credentials: false - name: Install toolchain run: rustup show active-toolchain @@ -188,6 +196,8 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + persist-credentials: false - name: Install toolchain run: rustup show active-toolchain diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index 2e5b5bd41dfbb..9e7adc2a5c34c 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -25,6 +25,9 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false - name: Install toolchain run: rustup show active-toolchain diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 32dc251c836f6..b42f3e7712f10 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -22,19 +22,27 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false - name: Checkout uses: actions/checkout@v4 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false # Run - name: Set tag name if: startswith(github.ref, 'refs/tags/') run: | - TAG=$(basename ${{ github.ref }}) + TAG=$(basename "${TAGNAME}") echo "TAG_NAME=$TAG" >> $GITHUB_ENV + env: + # Make sure that the reference gets expanded before injecting it + TAGNAME: ${{ github.ref }} - name: Set beta to true if: github.ref == 'refs/heads/beta' run: echo "BETA=true" >> $GITHUB_ENV diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml index 3cbda0b382436..64966f1d1898b 100644 --- a/.github/workflows/lintcheck.yml +++ b/.github/workflows/lintcheck.yml @@ -21,6 +21,8 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 2 + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^` # being the commit from `master` that is the base of the merge @@ -73,6 +75,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false - name: Cache lintcheck bin id: cache-lintcheck-bin @@ -103,6 +108,9 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false - name: Restore lintcheck bin uses: actions/cache/restore@v4 diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 0d402fe706410..69d00dc027e85 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -12,6 +12,9 @@ jobs: # Setup - name: Checkout uses: actions/checkout@v4 + with: + # Unsetting this would make so that any malicious package could get our Github Token + persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 From ad36f2b0539464e2c529f9d7da3f3f4f150282c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jan 2025 21:22:42 +0100 Subject: [PATCH 048/189] turn rustc_box into an intrinsic --- .../disallowed_macros/disallowed_macros.stderr | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/tests/ui-toml/disallowed_macros/disallowed_macros.stderr index 2e3386628b4d3..6a6c6168a1f59 100644 --- a/tests/ui-toml/disallowed_macros/disallowed_macros.stderr +++ b/tests/ui-toml/disallowed_macros/disallowed_macros.stderr @@ -1,12 +1,3 @@ -error: use of a disallowed macro `std::vec` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5 - | -LL | vec![1, 2, 3]; - | ^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-macros` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]` - error: use of a disallowed macro `serde::Serialize` --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:18:14 | @@ -14,6 +5,8 @@ LL | #[derive(Serialize)] | ^^^^^^^^^ | = note: no serializing + = note: `-D clippy::disallowed-macros` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]` error: use of a disallowed macro `macros::attr` --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:31:1 @@ -47,6 +40,12 @@ error: use of a disallowed macro `std::cfg` LL | cfg!(unix); | ^^^^^^^^^^ +error: use of a disallowed macro `std::vec` + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5 + | +LL | vec![1, 2, 3]; + | ^^^^^^^^^^^^^ + error: use of a disallowed macro `macros::expr` --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:21:13 | From 4736004c2c9c35ea94851294e9c61099ddb91ca8 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 3 Jan 2025 19:39:32 +0100 Subject: [PATCH 049/189] Update version attribute for 1.84 clippy lints --- clippy_lints/src/manual_ignore_case_cmp.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/unnecessary_literal_bound.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs index dabfac3f6137b..506f4f6d9de1b 100644 --- a/clippy_lints/src/manual_ignore_case_cmp.rs +++ b/clippy_lints/src/manual_ignore_case_cmp.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc") /// } /// ``` - #[clippy::version = "1.82.0"] + #[clippy::version = "1.84.0"] pub MANUAL_IGNORE_CASE_CMP, perf, "manual case-insensitive ASCII comparison" diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 2f77989b379fa..9443dca154e33 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -97,7 +97,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.83.0"] + #[clippy::version = "1.84.0"] pub REGEX_CREATION_IN_LOOPS, perf, "regular expression compilation performed in a loop" diff --git a/clippy_lints/src/unnecessary_literal_bound.rs b/clippy_lints/src/unnecessary_literal_bound.rs index 8165a45bc5baa..9f107fbeec03a 100644 --- a/clippy_lints/src/unnecessary_literal_bound.rs +++ b/clippy_lints/src/unnecessary_literal_bound.rs @@ -47,7 +47,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.83.0"] + #[clippy::version = "1.84.0"] pub UNNECESSARY_LITERAL_BOUND, pedantic, "detects &str that could be &'static str in function return types" From 4e4a2d022bfbb6740d78d82c37d1b6363948a18a Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 3 Jan 2025 19:40:39 +0100 Subject: [PATCH 050/189] Changelog for Clippy 1.84 :firecracker: --- CHANGELOG.md | 45 ++++++++++++++++++- .../infrastructure/changelog_update.md | 5 +++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e68b46cb0f67..e8d2060cacc56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,52 @@ document. ## Unreleased / Beta / In Rust Nightly -[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master) +[786fbd6d...master](https://github.com/rust-lang/rust-clippy/compare/786fbd6d...master) + +## Rust 1.84 + +Current stable, released 2024-01-09 + +[View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster) + +### New Lints + +* Added [`unnecessary_map_or`] to `style` + [#11796](https://github.com/rust-lang/rust-clippy/pull/11796) +* Added [`arbitrary_source_item_ordering`] to `restriction` + [#13376](https://github.com/rust-lang/rust-clippy/pull/13376) +* Added [`map_with_unused_argument_over_ranges`] to `restriction` + [#13034](https://github.com/rust-lang/rust-clippy/pull/13034) +* Added [`map_all_any_identity`] to `complexity` + [#13499](https://github.com/rust-lang/rust-clippy/pull/13499) +* Added [`needless_as_bytes`] to `complexity` + [#13437](https://github.com/rust-lang/rust-clippy/pull/13437) +* Added [`unnecessary_literal_bound`] to `pedantic` + [#13395](https://github.com/rust-lang/rust-clippy/pull/13395) +* Added [`manual_ignore_case_cmp`] to `perf` + [#13334](https://github.com/rust-lang/rust-clippy/pull/13334) +* Added [`regex_creation_in_loops`] to `perf` + [#13412](https://github.com/rust-lang/rust-clippy/pull/13412) + +### Moves and Deprecations + +* Moved [`manual_is_power_of_two`] to `pedantic` (From `complexity`, now allow-by-default) + [#13553](https://github.com/rust-lang/rust-clippy/pull/13553) +* Move [`module_name_repetitions`] to `restriction` (from `pedantic`) + [#13541](https://github.com/rust-lang/rust-clippy/pull/13541) + +### Enhancements + +* [`doc_markdown`]: Added the following identifiers to [`doc-valid-idents`]: + CoAP, MHz, GHz, and THz + [#13633](https://github.com/rust-lang/rust-clippy/pull/13633) + [#13460](https://github.com/rust-lang/rust-clippy/pull/13460) +* [`large_const_arrays`]: Changed the default of [`array-size-threshold`] to `16kb` (from `512kb`) + [#13485](https://github.com/rust-lang/rust-clippy/pull/13485) ## Rust 1.83 -Current stable, released 2024-11-28 +Released 2024-11-28 [View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster) diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index df9b1bbe18f32..2b2c096b0496f 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -83,7 +83,12 @@ As section headers, we use: ``` ### New Lints +* Added [`LINT`] to `GROUP` + ### Moves and Deprecations +* Moved [`LINT`] to `GROUP` (From `GROUP`, now LEVEL-by-default) +* Renamed `LINT` to [`LINT`] + ### Enhancements ### False Positive Fixes ### Suggestion Fixes/Improvements From e4193e2de8b1643361656d2cd10bc7402137f8e9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Jan 2025 19:39:39 +0000 Subject: [PATCH 051/189] Do not ICE when encountering predicates from other items in method error reporting --- .../rustc_hir_typeck/src/method/suggest.rs | 10 ++-- .../methods/bad-wf-when-selecting-method.rs | 18 +++++++ .../bad-wf-when-selecting-method.stderr | 54 +++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 tests/ui/methods/bad-wf-when-selecting-method.rs create mode 100644 tests/ui/methods/bad-wf-when-selecting-method.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0b008fd10b507..7875f6710e935 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1067,7 +1067,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) ) { continue; - }; + } match self.tcx.hir().get_if_local(item_def_id) { // Unmet obligation comes from a `derive` macro, point at it once to @@ -1181,8 +1181,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); entry.2.push(p); } - Some(node) => unreachable!("encountered `{node:?}` due to `{cause:#?}`"), - None => (), + _ => { + // It's possible to use well-formedness clauses to get obligations + // which point arbitrary items like ADTs, so there's no use in ICEing + // here if we find that the obligation originates from some other + // node that we don't handle. + } } } let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect(); diff --git a/tests/ui/methods/bad-wf-when-selecting-method.rs b/tests/ui/methods/bad-wf-when-selecting-method.rs new file mode 100644 index 0000000000000..638d1ffa982fa --- /dev/null +++ b/tests/ui/methods/bad-wf-when-selecting-method.rs @@ -0,0 +1,18 @@ +trait Wf { + type Assoc; +} + +struct Wrapper, U>(T); + +trait Trait { + fn needs_sized(self); +} + +fn test(t: T) { + Wrapper(t).needs_sized(); + //~^ ERROR the trait bound `T: Wf` is not satisfied + //~| ERROR the trait bound `T: Wf` is not satisfied + //~| the method `needs_sized` exists for struct `Wrapper`, but its trait bounds were not satisfied +} + +fn main() {} diff --git a/tests/ui/methods/bad-wf-when-selecting-method.stderr b/tests/ui/methods/bad-wf-when-selecting-method.stderr new file mode 100644 index 0000000000000..e6d500349670c --- /dev/null +++ b/tests/ui/methods/bad-wf-when-selecting-method.stderr @@ -0,0 +1,54 @@ +error[E0277]: the trait bound `T: Wf` is not satisfied + --> $DIR/bad-wf-when-selecting-method.rs:12:13 + | +LL | Wrapper(t).needs_sized(); + | ------- ^ the trait `Wf` is not implemented for `T` + | | + | required by a bound introduced by this call + | +note: required by a bound in `Wrapper` + --> $DIR/bad-wf-when-selecting-method.rs:5:19 + | +LL | struct Wrapper, U>(T); + | ^^^^^^^^^^^^^ required by this bound in `Wrapper` +help: consider restricting type parameter `T` with trait `Wf` + | +LL | fn test(t: T) { + | ++++ + +error[E0277]: the trait bound `T: Wf` is not satisfied + --> $DIR/bad-wf-when-selecting-method.rs:12:5 + | +LL | Wrapper(t).needs_sized(); + | ^^^^^^^^^^ the trait `Wf` is not implemented for `T` + | +note: required by a bound in `Wrapper` + --> $DIR/bad-wf-when-selecting-method.rs:5:19 + | +LL | struct Wrapper, U>(T); + | ^^^^^^^^^^^^^ required by this bound in `Wrapper` +help: consider restricting type parameter `T` with trait `Wf` + | +LL | fn test(t: T) { + | ++++ + +error[E0599]: the method `needs_sized` exists for struct `Wrapper`, but its trait bounds were not satisfied + --> $DIR/bad-wf-when-selecting-method.rs:12:16 + | +LL | struct Wrapper, U>(T); + | ----------------------------------- method `needs_sized` not found for this struct +... +LL | Wrapper(t).needs_sized(); + | ^^^^^^^^^^^ method cannot be called on `Wrapper` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `T: Wf` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | fn test(t: T) where T: Wf { + | +++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. From 1b85ae3a60740995c12dff830e0492289546388b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 31 Dec 2024 00:46:53 +0100 Subject: [PATCH 052/189] Only emit `useless_vec` suggestion if the macro does not contain code comments --- clippy_lints/src/vec.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index ef1c46154d29a..0730b561bc29e 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -8,7 +8,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method}; +use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -132,9 +132,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { for (span, lint_opt) in &self.span_to_lint_map { if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt { - let help_msg = format!("you can use {} directly", suggest_slice.desc(),); + let help_msg = format!("you can use {} directly", suggest_slice.desc()); span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| { - diag.span_suggestion(*span, help_msg, snippet, *applicability); + // If the `vec!` macro contains comment, better not make the suggestion machine + // applicable as it would remove them. + let applicability = if *applicability != Applicability::Unspecified + && let source_map = cx.tcx.sess.source_map() + && span_contains_comment(source_map, *span) + { + Applicability::Unspecified + } else { + *applicability + }; + diag.span_suggestion(*span, help_msg, snippet, applicability); }); } } From b76e0426a115310c454d1846d53b4d263180065c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 31 Dec 2024 00:47:11 +0100 Subject: [PATCH 053/189] Add regression test for `useless_vec` with code comments --- tests/ui/useless_vec.rs | 15 +++++++++++++++ tests/ui/useless_vec.stderr | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/useless_vec.rs create mode 100644 tests/ui/useless_vec.stderr diff --git a/tests/ui/useless_vec.rs b/tests/ui/useless_vec.rs new file mode 100644 index 0000000000000..880809f81d7ae --- /dev/null +++ b/tests/ui/useless_vec.rs @@ -0,0 +1,15 @@ +//@no-rustfix: no suggestions + +#![warn(clippy::useless_vec)] + +// Regression test for . +fn foo() { + // There should be no suggestion in this case. + let _some_variable = vec![ + //~^ useless_vec + 1, 2, // i'm here to stay + 3, 4, // but this one going away ;-; + ]; // that is life anyways +} + +fn main() {} diff --git a/tests/ui/useless_vec.stderr b/tests/ui/useless_vec.stderr new file mode 100644 index 0000000000000..e47364fb06d3b --- /dev/null +++ b/tests/ui/useless_vec.stderr @@ -0,0 +1,21 @@ +error: useless use of `vec!` + --> tests/ui/useless_vec.rs:8:26 + | +LL | let _some_variable = vec![ + | __________________________^ +LL | | +LL | | 1, 2, // i'm here to stay +LL | | 3, 4, // but this one going away ;-; +LL | | ]; // that is life anyways + | |_____^ + | + = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` +help: you can use an array directly + | +LL ~ let _some_variable = [1, 2, // i'm here to stay +LL ~ 3, 4]; // that is life anyways + | + +error: aborting due to 1 previous error + From f416f266b0fcd957b7c7dd939ebed15a5ebd939b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jan 2025 11:30:31 +0100 Subject: [PATCH 054/189] turn hir::ItemKind::Fn into a named-field variant --- clippy_lints/src/arbitrary_source_item_ordering.rs | 2 +- clippy_lints/src/attrs/utils.rs | 2 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/doc/too_long_first_doc_paragraph.rs | 2 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/extra_unused_type_parameters.rs | 6 +++++- clippy_lints/src/functions/must_use.rs | 7 ++++++- clippy_lints/src/functions/result.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 7 ++++++- clippy_lints/src/lifetimes.rs | 8 +++++++- clippy_lints/src/loops/infinite_loop.rs | 6 +++++- clippy_lints/src/matches/needless_match.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 2 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/returns.rs | 2 +- clippy_lints/src/unnecessary_box_returns.rs | 4 ++-- clippy_utils/src/check_proc_macro.rs | 2 +- clippy_utils/src/lib.rs | 6 +++--- 23 files changed, 50 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs index cf33e1444e47d..741539902662e 100644 --- a/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -464,7 +464,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte ItemKind::Use(..) => Use, ItemKind::Static(..) => Static, ItemKind::Const(..) => Const, - ItemKind::Fn(..) => Fn, + ItemKind::Fn{ .. } => Fn, ItemKind::Macro(..) => Macro, ItemKind::Mod(..) => Mod, ItemKind::ForeignMod { .. } => ForeignMod, diff --git a/clippy_lints/src/attrs/utils.rs b/clippy_lints/src/attrs/utils.rs index 96de064290400..152e6ec70a189 100644 --- a/clippy_lints/src/attrs/utils.rs +++ b/clippy_lints/src/attrs/utils.rs @@ -21,7 +21,7 @@ pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool { } pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Fn(_, _, eid) = item.kind { + if let ItemKind::Fn { body: eid, .. } = item.kind { is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) } else { true diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index b2135fe18bd9e..c835b81679b58 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -639,7 +639,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { self.check_private_items, ); match item.kind { - ItemKind::Fn(sig, _, body_id) => { + ItemKind::Fn { sig, body: body_id, .. } => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { diff --git a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs index 0f9ff55085327..2327da0ccff74 100644 --- a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -25,7 +25,7 @@ pub(super) fn check( // page. So associated items or impl blocks are not part of this list. ItemKind::Static(..) | ItemKind::Const(..) - | ItemKind::Fn(..) + | ItemKind::Fn{ .. } | ItemKind::Macro(..) | ItemKind::Mod(..) | ItemKind::TyAlias(..) diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 3c235fab0098b..e6ddcd107d9d3 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit { && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::process_exit, def_id) && let parent = cx.tcx.hir().get_parent_item(e.hir_id) - && let OwnerNode::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_owner_node(parent) + && let OwnerNode::Item(Item{kind: ItemKind::Fn{ .. }, ..}) = cx.tcx.hir_owner_node(parent) // If the next item up is a function we check if it is an entry point // and only then emit a linter warning && !is_entrypoint_fn(cx, parent.to_def_id()) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index ae4b668006529..d0159ab89e106 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -253,7 +253,11 @@ fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool { impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Fn(_, generics, body_id) = item.kind + if let ItemKind::Fn { + generics, + body: body_id, + .. + } = item.kind && !generics.params.is_empty() && !is_empty_body(cx, body_id) && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index afdb5d5306a6b..1a01f5f885c30 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -24,7 +24,12 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { + if let hir::ItemKind::Fn { + ref sig, + body: ref body_id, + .. + } = item.kind + { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 674d78eaae76a..9c396986f62ac 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -36,7 +36,7 @@ fn result_err_ty<'tcx>( } pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64, msrv: &Msrv) { - if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind + if let hir::ItemKind::Fn { ref sig, .. } = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { if cx.effective_visibilities.is_exported(item.owner_id.def_id) { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index c370f206c8f83..ad2da3c7fcd1e 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -149,7 +149,12 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { ); } }, - ItemKind::Fn(ref sig, generics, body_id) => { + ItemKind::Fn { + ref sig, + generics, + body: body_id, + .. + } => { let body = cx.tcx.hir().body(body_id); for ty in sig.decl.inputs { diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 8b2eee34a972a..239822f408569 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -95,7 +95,13 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Fn(ref sig, generics, id) = item.kind { + if let ItemKind::Fn { + ref sig, + generics, + body: id, + .. + } = item.kind + { check_fn_inner(cx, sig, Some(id), None, generics, item.span, true); } else if let ItemKind::Impl(impl_) = item.kind { if !item.span.from_expansion() { diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs index 9f543b79bac44..f88605fbea0dd 100644 --- a/clippy_lints/src/loops/infinite_loop.rs +++ b/clippy_lints/src/loops/infinite_loop.rs @@ -75,7 +75,11 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option .. }) => (), Node::Item(hir::Item { - kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _), + kind: + hir::ItemKind::Fn { + sig: FnSig { decl, .. }, + .. + }, .. }) | Node::TraitItem(hir::TraitItem { diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 73822314b4b4a..63bea586caf61 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_> }, // compare match_expr ty with RetTy in `fn foo() -> RetTy` Node::Item(item) => { - if let ItemKind::Fn(..) = item.kind { + if let ItemKind::Fn{ .. } = item.kind { let output = cx .tcx .fn_sig(item.owner_id) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index d19064fd57e3e..42107581ab468 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -496,7 +496,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Stmt(_) => return true, Node::Block(..) => continue, Node::Item(item) => { - if let ItemKind::Fn(_, _, body_id) = &item.kind + if let ItemKind::Fn { body: body_id, .. } = &item.kind && let output_ty = return_ty(cx, item.owner_id) && rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty) { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index b6f49dcc163f1..1141728640d41 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { match it.kind { - hir::ItemKind::Fn(..) => { + hir::ItemKind::Fn{ .. } => { // ignore main() if it.ident.name == sym::main { let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID; diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 11ff779d53161..b18f18d89e569 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { return; } match it.kind { - hir::ItemKind::Fn(..) => { + hir::ItemKind::Fn{ .. } => { let desc = "a function"; let attrs = cx.tcx.hir().attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 745f81d1c51ad..7abc5870d00e0 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -76,7 +76,7 @@ impl_lint_pass!(MutableKeyType<'_> => [ MUTABLE_KEY_TYPE ]); impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - if let hir::ItemKind::Fn(ref sig, ..) = item.kind { + if let hir::ItemKind::Fn { ref sig, .. } = item.kind { self.check_sig(cx, item.owner_id.def_id, sig.decl); } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 7feff7e4d3f13..92644456f63d1 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -144,7 +144,7 @@ impl NoEffect { |diag| { for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { if let Node::Item(item) = parent.1 - && let ItemKind::Fn(..) = item.kind + && let ItemKind::Fn{ .. } = item.kind && let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) && let [.., final_stmt] = block.stmts && final_stmt.hir_id == stmt.hir_id diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index 64587e08ddc6f..9ee4e49327775 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -37,7 +37,7 @@ declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]); impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Fn(fn_sig, _, _) = &item.kind { + if let ItemKind::Fn { sig: fn_sig, .. } = &item.kind { let attrs = cx.tcx.hir().attrs(item.hir_id()); let mut app = Applicability::MaybeIncorrect; let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(item.ident.span.lo()), "..", &mut app); diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index b674b01406d35..a86926d8416c6 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -189,7 +189,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { let mut parents = hir.parent_iter(body.value.hir_id); let (item_id, sig, is_trait_item) = match parents.next() { Some((_, Node::Item(i))) => { - if let ItemKind::Fn(sig, ..) = &i.kind { + if let ItemKind::Fn { sig, .. } = &i.kind { (i.owner_id, sig, false) } else { return; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index aeff31d02d26f..dfaee8cc3054d 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -204,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { // Ensure this is not the final stmt, otherwise removing it would cause a compile error && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id)) - && let ItemKind::Fn(_, _, body) = item.kind + && let ItemKind::Fn { body, .. } = item.kind && let block = cx.tcx.hir().body(body).value && let ExprKind::Block(block, _) = block.kind && !is_inside_let_else(cx.tcx, expr) diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 34df1d5560a12..4158050f969a8 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -130,9 +130,9 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns { } fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - let ItemKind::Fn(signature, ..) = &item.kind else { + let ItemKind::Fn { sig, .. } = &item.kind else { return; }; - self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); + self.check_fn_item(cx, sig.decl, item.owner_id.def_id, item.ident.name); } } diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index b71b53ea3bbfd..68e7f807bf514 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -245,7 +245,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")), ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")), ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), - ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + ItemKind::Fn { sig, .. } => (fn_header_search_pat(sig.header), Pat::Str("")), ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), ItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 77c597f853489..30e7471dd9258 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1397,7 +1397,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio enclosing_node.and_then(|node| match node { Node::Block(block) => Some(block), Node::Item(&Item { - kind: ItemKind::Fn(_, _, eid), + kind: ItemKind::Fn { body: eid, .. }, .. }) | Node::ImplItem(&ImplItem { @@ -2565,7 +2565,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { // function scope .any(|(_id, node)| { if let Node::Item(item) = node { - if let ItemKind::Fn(_, _, _) = item.kind { + if let ItemKind::Fn { .. } = item.kind { // Note that we have sorted the item names in the visitor, // so the binary_search gets the same as `contains`, but faster. return names.binary_search(&item.ident.name).is_ok(); @@ -2722,7 +2722,7 @@ impl<'tcx> ExprUseCtxt<'tcx> { }) => ExprUseNode::ConstStatic(owner_id), Node::Item(&Item { - kind: ItemKind::Fn(..), + kind: ItemKind::Fn { .. }, owner_id, .. }) From 622382b6c6b18bd36623ff0d2aa20b134c37a941 Mon Sep 17 00:00:00 2001 From: Fridtjof Stoldt Date: Sat, 4 Jan 2025 22:28:51 +0100 Subject: [PATCH 055/189] Fix year in CHANGELOG.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit copy-pasta got the better of me xD 🍝 Co-authored-by: Samuel Tardieu --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8d2060cacc56..1770e8095a01c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ document. ## Rust 1.84 -Current stable, released 2024-01-09 +Current stable, released 2025-01-09 [View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster) From 12d31375601b592c5451dd52de4633393229a9a2 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 4 Jan 2025 21:32:14 +0100 Subject: [PATCH 056/189] CI: be compatible with both Rustup pre-1.28.0 and 1.28.0 `rustup show active-toolchain` will no longer install the default toolchain starting from Rustup 1.28.0, and `rustup toolchain install` without extra arguments is not supported in Rustup pre-1.28.0. --- .github/workflows/clippy_mq.yml | 17 ++++++++++++----- .github/workflows/clippy_pr.yml | 4 +++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml index 078a278e21a89..dee7d028655e3 100644 --- a/.github/workflows/clippy_mq.yml +++ b/.github/workflows/clippy_mq.yml @@ -78,7 +78,8 @@ jobs: - name: Install toolchain run: | rustup set default-host ${{ matrix.host }} - rustup show active-toolchain + # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0 + rustup show active-toolchain || rustup toolchain install # Run - name: Build @@ -129,7 +130,9 @@ jobs: persist-credentials: false - name: Install toolchain - run: rustup show active-toolchain + run: | + # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0 + rustup show active-toolchain || rustup toolchain install - name: Test metadata collection run: cargo collect-metadata @@ -146,7 +149,9 @@ jobs: persist-credentials: false - name: Install toolchain - run: rustup show active-toolchain + run: | + # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0 + rustup show active-toolchain || rustup toolchain install # Run - name: Build Integration Test @@ -200,7 +205,9 @@ jobs: persist-credentials: false - name: Install toolchain - run: rustup show active-toolchain + run: | + # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0 + rustup show active-toolchain || rustup toolchain install # Download - name: Download target dir @@ -215,7 +222,7 @@ jobs: # Run - name: Test ${{ matrix.integration }} run: | - TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ') + TOOLCHAIN=$(rustup show active-toolchain | head -n 1 | cut -f1 -d' ') rustup run $TOOLCHAIN $CARGO_TARGET_DIR/debug/integration --show-output env: INTEGRATION: ${{ matrix.integration }} diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index 9e7adc2a5c34c..80523d91f4fc8 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -30,7 +30,9 @@ jobs: persist-credentials: false - name: Install toolchain - run: rustup show active-toolchain + run: | + # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0 + rustup show active-toolchain || rustup toolchain install # Run - name: Build From a2d78f77f48058fc58c3e56309b870ebeae90859 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 5 Jan 2025 15:44:46 +0000 Subject: [PATCH 057/189] Merge commit '918acafef682d0d0ca30b47de4768210417ff362' into sync_cg_clif-2025-01-05 --- .github/workflows/main.yml | 35 -------- Cargo.lock | 166 +++++++++++++++--------------------- Cargo.toml | 12 +-- build_system/bench.rs | 47 ++++------ build_system/config.rs | 20 ----- build_system/main.rs | 16 ++-- build_system/path.rs | 16 ++-- config.txt | 10 --- patches/bcryptprimitives.rs | 22 ----- rust-toolchain | 2 +- scripts/test_rustc_tests.sh | 7 +- src/driver/aot.rs | 7 +- src/driver/jit.rs | 2 +- src/inline_asm.rs | 2 +- src/intrinsics/simd.rs | 2 +- src/lib.rs | 3 + 16 files changed, 120 insertions(+), 249 deletions(-) delete mode 100644 patches/bcryptprimitives.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2ee94146c1a4e..a8333df77e6e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,11 +56,6 @@ jobs: - os: macos-latest env: TARGET_TRIPLE: x86_64-apple-darwin - # cross-compile from Linux to Windows using mingw - - os: ubuntu-latest - env: - TARGET_TRIPLE: x86_64-pc-windows-gnu - apt_deps: gcc-mingw-w64-x86-64 wine-stable - os: ubuntu-latest env: TARGET_TRIPLE: aarch64-unknown-linux-gnu @@ -113,15 +108,6 @@ jobs: - name: Prepare dependencies run: ./y.sh prepare - # The Wine version shipped with Ubuntu 22.04 doesn't implement bcryptprimitives.dll - - name: Build bcryptprimitives.dll shim for Wine - if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' - run: | - rustup target add x86_64-pc-windows-gnu - mkdir wine_shims - rustc patches/bcryptprimitives.rs -Copt-level=3 -Clto=fat --out-dir wine_shims --target x86_64-pc-windows-gnu - echo "WINEPATH=$(pwd)/wine_shims" >> $GITHUB_ENV - - name: Build run: ./y.sh build --sysroot none @@ -135,9 +121,6 @@ jobs: # This is roughly config rust-lang/rust uses for testing - name: Test with LLVM sysroot - # Skip native x86_64-pc-windows-gnu. It is way too slow and cross-compiled - # x86_64-pc-windows-gnu covers at least part of the tests. - if: matrix.os != 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' env: TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }} run: ./y.sh test --sysroot llvm --no-unstable-features @@ -215,10 +198,6 @@ jobs: - os: macos-latest env: TARGET_TRIPLE: aarch64-apple-darwin - # cross-compile from Linux to Windows using mingw - - os: ubuntu-latest - env: - TARGET_TRIPLE: x86_64-pc-windows-gnu - os: windows-latest env: TARGET_TRIPLE: x86_64-pc-windows-msvc @@ -243,12 +222,6 @@ jobs: if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' run: rustup set default-host x86_64-apple-darwin - - name: Install MinGW toolchain - if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-mingw-w64-x86-64 - - name: Prepare dependencies run: ./y.sh prepare @@ -262,19 +235,11 @@ jobs: run: tar cvfJ cg_clif.tar.xz dist - name: Upload prebuilt cg_clif - if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' uses: actions/upload-artifact@v4 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz - - name: Upload prebuilt cg_clif (cross compile) - if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v4 - with: - name: cg_clif-${{ runner.os }}-cross-x86_64-mingw - path: cg_clif.tar.xz - release: runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/Cargo.lock b/Cargo.lock index d81e7214961f6..ec71370ef9e7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,22 +3,16 @@ version = 4 [[package]] -name = "ahash" -version = "0.8.11" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arbitrary" @@ -37,6 +31,9 @@ name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] [[package]] name = "cfg-if" @@ -46,24 +43,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1" +checksum = "ac89549be94911dd0e839b4a7db99e9ed29c17517e1c026f61066884c168aa3c" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156" +checksum = "b9bd49369f76c77e34e641af85d0956869237832c118964d08bf5f51f210875a" [[package]] name = "cranelift-codegen" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b" +checksum = "fd96ce9cf8efebd7f5ab8ced5a0ce44250280bbae9f593d74a6d7effc3582a35" dependencies = [ "bumpalo", "cranelift-bforest", @@ -74,7 +71,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown", + "hashbrown 0.14.5", "log", "regalloc2", "rustc-hash", @@ -85,42 +82,42 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7" +checksum = "5a68e358827afe4bfb6239fcbf6fbd5ac56206ece8a99c8f5f9bbd518773281a" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895" +checksum = "e184c9767afbe73d50c55ec29abcf4c32f9baf0d9d22b86d58c4d55e06dee181" [[package]] name = "cranelift-control" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec" +checksum = "5cc7664f2a66f053e33f149e952bb5971d138e3af637f5097727ed6dc0ed95dd" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96" +checksum = "118597e3a9cf86c3556fa579a7a23b955fa18231651a52a77a2475d305a9cf84" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e" +checksum = "7638ea1efb069a0aa18d8ee67401b6b0d19f6bfe5de5e9ede348bfc80bb0d8c7" dependencies = [ "cranelift-codegen", "log", @@ -130,15 +127,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8" +checksum = "15c53e1152a0b01c4ed2b1e0535602b8e86458777dd9d18b28732b16325c7dc0" [[package]] name = "cranelift-jit" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe" +checksum = "36972cab12ff246afe8d45b6a427669cf814bd393c661e5e8a8dedc26a81c73f" dependencies = [ "anyhow", "cranelift-codegen", @@ -156,9 +153,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977" +checksum = "11841b3f54ac480db1e8e8d5678ba901a13b387012d315e3f8fba3e7b7a80447" dependencies = [ "anyhow", "cranelift-codegen", @@ -167,9 +164,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f" +checksum = "7b7d8f895444fa52dd7bdd0bed11bf007a7fb43af65a6deac8fcc4094c6372f7" dependencies = [ "cranelift-codegen", "libc", @@ -178,9 +175,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.114.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd" +checksum = "8e235ddfd19f100855ad03358c7ae0a13070c38a000701054cab46458cca6e81" dependencies = [ "anyhow", "cranelift-codegen", @@ -212,6 +209,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "gimli" version = "0.31.1" @@ -228,18 +231,24 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "ahash", + "foldhash", ] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -281,27 +290,21 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "object" -version = "0.36.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", - "hashbrown", + "hashbrown 0.15.2", "indexmap", "memchr", ] -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -317,14 +320,15 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.10.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0" +checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" dependencies = [ - "hashbrown", + "allocator-api2", + "bumpalo", + "hashbrown 0.15.2", "log", "rustc-hash", - "slice-group-by", "smallvec", ] @@ -366,30 +370,24 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "slice-group-by" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" - [[package]] name = "smallvec" version = "1.13.2" @@ -404,9 +402,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.70" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -425,17 +423,11 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "wasmtime-jit-icache-coherence" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad" +checksum = "d40d7722b9e1fbeae135715710a8a2570b1e6cf72b74dd653962d89831c6c70d" dependencies = [ "anyhow", "cfg-if", @@ -524,23 +516,3 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index b2fed3c490edb..82d2b6cb2c4ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.114.0" } -cranelift-module = { version = "0.114.0" } -cranelift-native = { version = "0.114.0" } -cranelift-jit = { version = "0.114.0", optional = true } -cranelift-object = { version = "0.114.0" } +cranelift-codegen = { version = "0.115.0", default-features = false, features = ["std", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.115.0" } +cranelift-module = { version = "0.115.0" } +cranelift-native = { version = "0.115.0" } +cranelift-jit = { version = "0.115.0", optional = true } +cranelift-object = { version = "0.115.0" } target-lexicon = "0.12.0" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } diff --git a/build_system/bench.rs b/build_system/bench.rs index 73a0f325fc212..8359b7b527903 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -16,11 +16,7 @@ static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github( "", ); -pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { - benchmark_simple_raytracer(dirs, bootstrap_host_compiler); -} - -fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { +pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { if std::process::Command::new("hyperfine").output().is_err() { eprintln!("Hyperfine not installed"); eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine"); @@ -39,9 +35,9 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { }; eprintln!("[BENCH COMPILE] ebobby/simple-raytracer"); - let cargo_clif = dirs - .dist_dir - .join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-")); + let cargo_clif = &compiler.cargo; + let rustc_clif = &compiler.rustc; + let rustflags = &compiler.rustflags.join("\x1f"); let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml"); let target_dir = dirs.build_dir.join("simple_raytracer"); @@ -56,22 +52,24 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { target_dir = target_dir.display(), ); let clif_build_cmd = format!( - "RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif", + "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif", cargo_clif = cargo_clif.display(), + rustc_clif = rustc_clif.display(), manifest_path = manifest_path.display(), target_dir = target_dir.display(), ); let clif_build_opt_cmd = format!( - "RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt", + "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt", cargo_clif = cargo_clif.display(), + rustc_clif = rustc_clif.display(), manifest_path = manifest_path.display(), target_dir = target_dir.display(), ); - let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md"); + let bench_compile_markdown = dirs.build_dir.join("bench_compile.md"); let bench_compile = hyperfine_command( - 1, + 0, bench_runs, Some(&clean_cmd), &[ @@ -92,23 +90,14 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { eprintln!("[BENCH RUN] ebobby/simple-raytracer"); - let bench_run_markdown = dirs.dist_dir.join("bench_run.md"); - - let raytracer_cg_llvm = Path::new(".").join(get_file_name( - &bootstrap_host_compiler.rustc, - "raytracer_cg_llvm", - "bin", - )); - let raytracer_cg_clif = Path::new(".").join(get_file_name( - &bootstrap_host_compiler.rustc, - "raytracer_cg_clif", - "bin", - )); - let raytracer_cg_clif_opt = Path::new(".").join(get_file_name( - &bootstrap_host_compiler.rustc, - "raytracer_cg_clif_opt", - "bin", - )); + let bench_run_markdown = dirs.build_dir.join("bench_run.md"); + + let raytracer_cg_llvm = + Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin")); + let raytracer_cg_clif = + Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin")); + let raytracer_cg_clif_opt = + Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin")); let mut bench_run = hyperfine_command( 0, bench_runs, diff --git a/build_system/config.rs b/build_system/config.rs index ef540cf1f822b..37bc4c5d78275 100644 --- a/build_system/config.rs +++ b/build_system/config.rs @@ -33,23 +33,3 @@ pub(crate) fn get_bool(name: &str) -> bool { true } } - -pub(crate) fn get_value(name: &str) -> Option { - let values = load_config_file() - .into_iter() - .filter(|(key, _)| key == name) - .map(|(_, val)| val) - .collect::>(); - if values.is_empty() { - None - } else if values.len() == 1 { - if values[0].is_none() { - eprintln!("Config `{}` missing value", name); - process::exit(1); - } - values.into_iter().next().unwrap() - } else { - eprintln!("Config `{}` given multiple values: {:?}", name, values); - process::exit(1); - } -} diff --git a/build_system/main.rs b/build_system/main.rs index 99e6146657f34..3ff9751a3ef2d 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -156,10 +156,8 @@ fn main() { let cargo = rustc_info::get_cargo_path(); let rustc = rustc_info::get_rustc_path(); let rustdoc = rustc_info::get_rustdoc_path(); - let triple = std::env::var("HOST_TRIPLE") - .ok() - .or_else(|| config::get_value("host")) - .unwrap_or_else(|| rustc_info::get_host_triple(&rustc)); + let triple = + std::env::var("HOST_TRIPLE").unwrap_or_else(|_| rustc_info::get_host_triple(&rustc)); Compiler { cargo, rustc, @@ -170,10 +168,8 @@ fn main() { runner: vec![], } }; - let target_triple = std::env::var("TARGET_TRIPLE") - .ok() - .or_else(|| config::get_value("target")) - .unwrap_or_else(|| bootstrap_host_compiler.triple.clone()); + let target_triple = + std::env::var("TARGET_TRIPLE").unwrap_or_else(|_| bootstrap_host_compiler.triple.clone()); let dirs = path::Dirs { source_dir: current_dir.clone(), @@ -247,7 +243,7 @@ fn main() { ); } Command::Bench => { - build_sysroot::build_sysroot( + let compiler = build_sysroot::build_sysroot( &dirs, sysroot_kind, &cg_clif_dylib, @@ -255,7 +251,7 @@ fn main() { rustup_toolchain_name.as_deref(), target_triple, ); - bench::benchmark(&dirs, &bootstrap_host_compiler); + bench::benchmark(&dirs, &compiler); } } } diff --git a/build_system/path.rs b/build_system/path.rs index 20a81156b71d9..d6a6558b2be29 100644 --- a/build_system/path.rs +++ b/build_system/path.rs @@ -11,20 +11,11 @@ pub(crate) struct Dirs { #[doc(hidden)] #[derive(Debug, Copy, Clone)] -pub(crate) enum PathBase { +enum PathBase { Source, Build, } -impl PathBase { - fn to_path(self, dirs: &Dirs) -> PathBuf { - match self { - PathBase::Source => dirs.source_dir.clone(), - PathBase::Build => dirs.build_dir.clone(), - } - } -} - #[derive(Debug, Copy, Clone)] pub(crate) struct RelPath { base: PathBase, @@ -41,6 +32,9 @@ impl RelPath { } pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf { - self.base.to_path(dirs).join(self.suffix) + match self.base { + PathBase::Source => dirs.source_dir.join(self.suffix), + PathBase::Build => dirs.build_dir.join(self.suffix), + } } } diff --git a/config.txt b/config.txt index b63597f60fc6f..9808ad624e11c 100644 --- a/config.txt +++ b/config.txt @@ -1,15 +1,5 @@ # This file allows configuring the build system. -# Which triple to produce a compiler toolchain for. -# -# Defaults to the default triple of rustc on the host system. -#host = x86_64-unknown-linux-gnu - -# Which triple to build libraries (core/alloc/std/test/proc_macro) for. -# -# Defaults to `host`. -#target = x86_64-unknown-linux-gnu - # Disables cleaning of the sysroot dir. This will cause old compiled artifacts to be re-used when # the sysroot source hasn't changed. This is useful when the codegen backend hasn't been modified. # This option can be changed while the build system is already running for as long as sysroot diff --git a/patches/bcryptprimitives.rs b/patches/bcryptprimitives.rs deleted file mode 100644 index 4d186485aac1d..0000000000000 --- a/patches/bcryptprimitives.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Shim for bcryptprimitives.dll. The Wine version shipped with Ubuntu 22.04 -// doesn't support it yet. Authored by @ChrisDenton - -#![crate_type = "cdylib"] -#![allow(nonstandard_style)] - -#[no_mangle] -pub unsafe extern "system" fn ProcessPrng(mut pbData: *mut u8, mut cbData: usize) -> i32 { - while cbData > 0 { - let size = core::cmp::min(cbData, u32::MAX as usize); - RtlGenRandom(pbData, size as u32); - cbData -= size; - pbData = pbData.add(size); - } - 1 -} - -#[link(name = "advapi32")] -extern "system" { - #[link_name = "SystemFunction036"] - pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8; -} diff --git a/rust-toolchain b/rust-toolchain index 8d935df4d1f2f..4b97f21057982 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-12-06" +channel = "nightly-2025-01-05" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index e291ec204649e..442d61c6ade17 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -123,12 +123,17 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift +rm tests/ui/invalid-compile-flags/crate-type-flag.rs # warning about proc-macros and panic=abort # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended # ============================================================ rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump +rm -r tests/run-make/strip # same rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source +rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features +rm -r tests/run-make/const-trait-stable-toolchain # same +rm -r tests/run-make/incr-add-rust-src-component # genuine bugs # ============ @@ -196,5 +201,5 @@ index e7ae773ffa1d3..04bc2d7787da7 100644 EOF echo "[TEST] rustc test suite" -COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,ui,incremental} +COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental} popd diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 4fc30b69123dd..fe578e44770f7 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -333,10 +333,9 @@ fn make_module(sess: &Session, name: String) -> UnwindModule { let mut builder = ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); - // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size - // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections - // can easily double the amount of time necessary to perform linking. - builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false)); + builder.per_function_section( + sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections), + ); UnwindModule::new(ObjectModule::new(builder), true) } diff --git a/src/driver/jit.rs b/src/driver/jit.rs index eaab3362c7e83..9ca930e14da58 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -287,7 +287,7 @@ fn dep_symbol_lookup_fn( let mut dylib_paths = Vec::new(); - let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable].1; + let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable]; // `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to // get a postorder which ensures that all dependencies of a dylib are loaded before the dylib // itself. This helps the dynamic linker to find dylibs not in the regular dynamic library diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 33726056cc1cb..6ff75f75d3b28 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -136,7 +136,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( fx.bcx.ins().jump(destination_block, &[]); } None => { - fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap()); + fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap()); } } } diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index e0ebe30752afa..6d71b8e8abab4 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -1136,7 +1136,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _ => { fx.tcx.dcx().span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic)); // Prevent verifier error - fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap()); + fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap()); return; } } diff --git a/src/lib.rs b/src/lib.rs index c38ef82e5b80c..dc5d80e7a3451 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,8 @@ extern crate rustc_metadata; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; +#[macro_use] +extern crate tracing; // This prevents duplicating functions and statics that are already part of the host rustc process. #[allow(unused_extern_crates)] @@ -208,6 +210,7 @@ impl CodegenBackend for CraneliftCodegenBackend { need_metadata_module: bool, ) -> Box { tcx.dcx().abort_if_errors(); + info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.clone().unwrap_or_else(|| { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) .unwrap_or_else(|err| tcx.sess.dcx().fatal(err)) From ca55534c920fdd152c44ccb4051e928b8ffc94e6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 4 Jan 2025 20:25:41 +0500 Subject: [PATCH 058/189] Do not trigger clippy::missing_const_for_fn triggering for tests --- clippy_lints/src/missing_const_for_fn.rs | 9 ++++-- .../ui/missing_const_for_fn/cant_be_const.rs | 29 ++++++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 121c4326d6488..2572e186ce6cb 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; -use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method}; use rustc_errors::Applicability; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; @@ -97,6 +97,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, def_id: LocalDefId, ) { + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); + if is_in_test(cx.tcx, hir_id) { + return; + } + if !self.msrv.meets(msrvs::CONST_IF_MATCH) { return; } @@ -136,8 +141,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { return; } - let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); - // Const fns are not allowed as methods in a trait. { let parent = cx.tcx.hir().get_parent_item(hir_id).def_id; diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index ca323dcf17336..d2f9e34a5ceb3 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -47,7 +47,34 @@ fn get_y() -> u32 { Y } -// Don't lint entrypoint functions +#[cfg(test)] +mod with_test_fn { + #[derive(Clone, Copy)] + pub struct Foo { + pub n: u32, + } + + impl Foo { + #[must_use] + pub const fn new(n: u32) -> Foo { + Foo { n } + } + } + + #[test] + fn foo_is_copy() { + let foo = Foo::new(42); + let one = foo; + let two = foo; + _ = one; + _ = two; + } +} + +// Allowing on this function, because it would lint, which we don't want in this case. +// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped +// working +#[allow(clippy::missing_const_for_fn)] #[start] fn init(num: isize, something: *const *const u8) -> isize { 1 From fc7ee238d1f6d365e9a51b22e734c181c1723c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 6 Jan 2025 14:20:54 +0000 Subject: [PATCH 059/189] address review comments push constraint creation to where the statement/terminator info is gathered --- .../src/polonius/typeck_constraints.rs | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index c04661fbbc1a9..8235b844886e0 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -52,7 +52,7 @@ pub(super) fn convert_typeck_constraints<'tcx>( // this information better in MIR typeck instead, for example with a new `Locations` // variant that contains which node is crossing over between entry and exit. let point = liveness.point_from_location(location); - let (from, to) = if let Some(stmt) = + let localized_constraint = if let Some(stmt) = body[location.block].statements.get(location.statement_index) { localize_statement_constraint( @@ -78,19 +78,14 @@ pub(super) fn convert_typeck_constraints<'tcx>( universal_regions, ) }; - localized_outlives_constraints.push(LocalizedOutlivesConstraint { - source: outlives_constraint.sup, - from, - target: outlives_constraint.sub, - to, - }); + localized_outlives_constraints.push(localized_constraint); } } } } -/// For a given outlives constraint arising from a MIR statement, computes the CFG `from`-`to` -/// intra-block nodes to localize the constraint. +/// For a given outlives constraint arising from a MIR statement, localize the constraint with the +/// needed CFG `from`-`to` intra-block nodes. fn localize_statement_constraint<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -100,7 +95,7 @@ fn localize_statement_constraint<'tcx>( current_location: Location, current_point: PointIndex, universal_regions: &UniversalRegions<'tcx>, -) -> (PointIndex, PointIndex) { +) -> LocalizedOutlivesConstraint { match &stmt.kind { StatementKind::Assign(box (lhs, rhs)) => { // To create localized outlives constraints without midpoints, we rely on the property @@ -157,13 +152,18 @@ fn localize_statement_constraint<'tcx>( } _ => { // For the other cases, we localize an outlives constraint to where it arises. - (current_point, current_point) + LocalizedOutlivesConstraint { + source: outlives_constraint.sup, + from: current_point, + target: outlives_constraint.sub, + to: current_point, + } } } } -/// For a given outlives constraint arising from a MIR terminator, computes the CFG `from`-`to` -/// inter-block nodes to localize the constraint. +/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the +/// needed CFG `from`-`to` inter-block nodes. fn localize_terminator_constraint<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -172,7 +172,7 @@ fn localize_terminator_constraint<'tcx>( outlives_constraint: &OutlivesConstraint<'tcx>, current_point: PointIndex, universal_regions: &UniversalRegions<'tcx>, -) -> (PointIndex, PointIndex) { +) -> LocalizedOutlivesConstraint { // FIXME: check if other terminators need the same handling as `Call`s, in particular // Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some // coroutine tests, and that may be why. @@ -198,14 +198,19 @@ fn localize_terminator_constraint<'tcx>( // Typeck constraints guide loans between regions at the current point, so we do that in // the general case, and liveness will take care of making them flow to the terminator's // successors. - (current_point, current_point) + LocalizedOutlivesConstraint { + source: outlives_constraint.sup, + from: current_point, + target: outlives_constraint.sub, + to: current_point, + } } } } - -/// For a given constraint, returns the `from`-`to` edge according to whether the constraint flows -/// to or from a free region in the given `value`, some kind of result for an effectful operation, -/// like the LHS of an assignment. +/// For a given outlives constraint and CFG edge, returns the localized constraint with the +/// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to +/// or from a free region in the given `value`, some kind of result for an effectful operation, like +/// the LHS of an assignment. fn compute_constraint_direction<'tcx>( tcx: TyCtxt<'tcx>, outlives_constraint: &OutlivesConstraint<'tcx>, @@ -213,7 +218,7 @@ fn compute_constraint_direction<'tcx>( current_point: PointIndex, successor_point: PointIndex, universal_regions: &UniversalRegions<'tcx>, -) -> (PointIndex, PointIndex) { +) -> LocalizedOutlivesConstraint { let mut to = current_point; let mut from = current_point; tcx.for_each_free_region(value, |region| { @@ -227,5 +232,10 @@ fn compute_constraint_direction<'tcx>( } }); - (from, to) + LocalizedOutlivesConstraint { + source: outlives_constraint.sup, + from, + target: outlives_constraint.sub, + to, + } } From 4bc6b768714c16f9004f8f97b9e8f9aebbec9063 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 21 Dec 2024 10:34:34 +0100 Subject: [PATCH 060/189] Escape all `*` in rustc's SUMMARY.md --- src/doc/rustc/src/SUMMARY.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index d7e368cc87f2e..6ef81eee88134 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -70,8 +70,8 @@ - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) - [powerpc64le-unknown-linux-musl](platform-support/powerpc64le-unknown-linux-musl.md) - - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) - - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) + - [riscv32e\*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) + - [riscv32i\*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) @@ -80,14 +80,14 @@ - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - [sparcv9-sun-solaris](platform-support/solaris.md) - - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) + - [\*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) - - [*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md) - - [*-unknown-hermit](platform-support/hermit.md) - - [*-unknown-freebsd](platform-support/freebsd.md) + - [\*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md) + - [\*-unknown-hermit](platform-support/hermit.md) + - [\*-unknown-freebsd](platform-support/freebsd.md) - [\*-unknown-netbsd\*](platform-support/netbsd.md) - - [*-unknown-openbsd](platform-support/openbsd.md) - - [*-unknown-redox](platform-support/redox.md) + - [\*-unknown-openbsd](platform-support/openbsd.md) + - [\*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [\*-uwp-windows-msvc](platform-support/uwp-windows-msvc.md) - [\*-wrs-vxworks](platform-support/vxworks.md) @@ -104,7 +104,7 @@ - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [xtensa-\*-none-elf](platform-support/xtensa.md) - - [*-nuttx-\*](platform-support/nuttx.md) + - [\*-nuttx-\*](platform-support/nuttx.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) - [Custom Targets](targets/custom.md) From 8630234ebcb52e93ea2af90308887be151ab4a4a Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 6 Jan 2025 15:32:17 +0100 Subject: [PATCH 061/189] Add new `{x86_64,i686}-win7-windows-gnu` targets These are in symmetry with `{x86_64,i686}-win7-windows-msvc`. --- compiler/rustc_target/src/spec/mod.rs | 4 +- .../src/spec/targets/i686_win7_windows_gnu.rs | 35 ++++++++++++++ .../spec/targets/x86_64_win7_windows_gnu.rs | 32 +++++++++++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 + .../src/platform-support/win7-windows-gnu.md | 48 +++++++++++++++++++ .../src/platform-support/win7-windows-msvc.md | 8 +++- tests/assembly/targets/targets-pe.rs | 6 +++ 8 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs create mode 100644 src/doc/rustc/src/platform-support/win7-windows-gnu.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0dc1d795a8edc..a149f682c560e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1812,9 +1812,11 @@ supported_targets! { ("aarch64-unknown-illumos", aarch64_unknown_illumos), ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), + ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu), + ("x86_64-win7-windows-gnu", x86_64_win7_windows_gnu), ("i686-pc-windows-gnu", i686_pc_windows_gnu), ("i686-uwp-windows-gnu", i686_uwp_windows_gnu), - ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu), + ("i686-win7-windows-gnu", i686_win7_windows_gnu), ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm), ("i686-pc-windows-gnullvm", i686_pc_windows_gnullvm), diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs new file mode 100644 index 0000000000000..086a799a68c3b --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs @@ -0,0 +1,35 @@ +use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, base}; + +pub(crate) fn target() -> Target { + let mut base = base::windows_gnu::opts(); + base.vendor = "win7".into(); + base.cpu = "pentium4".into(); + base.max_atomic_width = Some(64); + base.frame_pointer = FramePointer::Always; // Required for backtraces + base.linker = Some("i686-w64-mingw32-gcc".into()); + + // Mark all dynamic libraries and executables as compatible with the larger 4GiB address + // space available to x86 Windows binaries on x86_64. + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &[ + "-m", + "i386pe", + "--large-address-aware", + ]); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]); + + Target { + llvm_target: "i686-pc-windows-gnu".into(), + metadata: crate::spec::TargetMetadata { + description: Some("32-bit MinGW (Windows 7+)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 32, + data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ + i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" + .into(), + arch: "x86".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs new file mode 100644 index 0000000000000..d40df5a3e7d64 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs @@ -0,0 +1,32 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, Target, base}; + +pub(crate) fn target() -> Target { + let mut base = base::windows_gnu::opts(); + base.vendor = "win7".into(); + base.cpu = "x86-64".into(); + base.plt_by_default = false; + // Use high-entropy 64 bit address space for ASLR + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &[ + "-m", + "i386pep", + "--high-entropy-va", + ]); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]); + base.max_atomic_width = Some(64); + base.linker = Some("x86_64-w64-mingw32-gcc".into()); + + Target { + llvm_target: "x86_64-pc-windows-gnu".into(), + metadata: crate::spec::TargetMetadata { + description: Some("64-bit MinGW (Windows 7+)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 64, + data_layout: + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 6ef81eee88134..670e4bd1be68b 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -98,6 +98,7 @@ - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md) - [wasm32v1-none](platform-support/wasm32v1-none.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) + - [\*-win7-windows-gnu](platform-support/win7-windows-gnu.md) - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md) - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) - [x86_64-pc-solaris](platform-support/solaris.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index a68efcda1f303..deeabd810d3da 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -313,6 +313,7 @@ target | std | host | notes [`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] [`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI] +[`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 32-bit Windows 7 support [^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`](platform-support/vxworks.md) | ✓ | | [^x86_32-floats-return-ABI] [`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | LoongArch64 OpenHarmony @@ -410,6 +411,7 @@ target | std | host | notes [`x86_64-unknown-trusty`](platform-support/trusty.md) | ? | | `x86_64-uwp-windows-gnu` | ✓ | | [`x86_64-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | +[`x86_64-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 64-bit Windows 7 support [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 64-bit Windows 7 support [`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell) diff --git a/src/doc/rustc/src/platform-support/win7-windows-gnu.md b/src/doc/rustc/src/platform-support/win7-windows-gnu.md new file mode 100644 index 0000000000000..180a1dc6d2650 --- /dev/null +++ b/src/doc/rustc/src/platform-support/win7-windows-gnu.md @@ -0,0 +1,48 @@ +# \*-win7-windows-gnu + +**Tier: 3** + +Windows targets continuing support of Windows 7. + +Target triples: +- `i686-win7-windows-gnu` +- `x86_64-win7-windows-gnu` + +## Target maintainers + +- @tbu- + +## Requirements + +This target supports all of core, alloc, std and test. Host +tools may also work, though those are not currently tested. + +Those targets follow Windows calling convention for extern "C". + +Like any other Windows target, the created binaries are in PE format. + +## Building the target + +You can build Rust with support for the targets by adding it to the target list in config.toml: + +```toml +[build] +build-stage = 1 +target = ["x86_64-win7-windows-gnu"] +``` + +## Building Rust programs + +Rust does not ship pre-compiled artifacts for this target. To compile for this +target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy by using `build-std` or +similar. + +## Testing + +Created binaries work fine on Windows or Wine using native hardware. Remote +testing is possible using the `remote-test-server` described [here](https://rustc-dev-guide.rust-lang.org/tests/running.html#running-tests-on-a-remote-machine). + +## Cross-compilation toolchains and C code + +Compatible C code can be built with gcc's `{i686,x86_64}-w64-mingw32-gcc`. diff --git a/src/doc/rustc/src/platform-support/win7-windows-msvc.md b/src/doc/rustc/src/platform-support/win7-windows-msvc.md index 45b00a2be8294..77b7d68212bf3 100644 --- a/src/doc/rustc/src/platform-support/win7-windows-msvc.md +++ b/src/doc/rustc/src/platform-support/win7-windows-msvc.md @@ -1,8 +1,12 @@ -# *-win7-windows-msvc +# \*-win7-windows-msvc **Tier: 3** -Windows targets continuing support of windows7. +Windows targets continuing support of Windows 7. + +Target triples: +- `i686-win7-windows-msvc` +- `x86_64-win7-windows-msvc` ## Target maintainers diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs index 6415aee6fae90..ab74de5c8ec42 100644 --- a/tests/assembly/targets/targets-pe.rs +++ b/tests/assembly/targets/targets-pe.rs @@ -39,6 +39,9 @@ //@ revisions: i686_uwp_windows_gnu //@ [i686_uwp_windows_gnu] compile-flags: --target i686-uwp-windows-gnu //@ [i686_uwp_windows_gnu] needs-llvm-components: x86 +//@ revisions: i686_win7_windows_gnu +//@ [i686_win7_windows_gnu] compile-flags: --target i686-win7-windows-gnu +//@ [i686_win7_windows_gnu] needs-llvm-components: x86 //@ revisions: i686_unknown_uefi //@ [i686_unknown_uefi] compile-flags: --target i686-unknown-uefi //@ [i686_unknown_uefi] needs-llvm-components: x86 @@ -72,6 +75,9 @@ //@ revisions: x86_64_uwp_windows_gnu //@ [x86_64_uwp_windows_gnu] compile-flags: --target x86_64-uwp-windows-gnu //@ [x86_64_uwp_windows_gnu] needs-llvm-components: x86 +//@ revisions: x86_64_win7_windows_gnu +//@ [x86_64_win7_windows_gnu] compile-flags: --target x86_64-win7-windows-gnu +//@ [x86_64_win7_windows_gnu] needs-llvm-components: x86 //@ revisions: x86_64_uwp_windows_msvc //@ [x86_64_uwp_windows_msvc] compile-flags: --target x86_64-uwp-windows-msvc //@ [x86_64_uwp_windows_msvc] needs-llvm-components: x86 From 891e38788a36c3d217e4e06d52e4ee67797b8ccb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2025 12:54:19 +0100 Subject: [PATCH 062/189] Don't emit machine applicable `map_flatten` lint if there are code comments --- clippy_lints/src/methods/map_flatten.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 07a7a12b16279..f7bb8c1d696de 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_trait_method, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -17,10 +17,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_ let mut applicability = Applicability::MachineApplicable; let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability); + let span = expr.span.with_lo(map_span.lo()); + // If the methods are separated with comments, we don't apply suggestion automatically. + if span_contains_comment(cx.tcx.sess.source_map(), span) { + applicability = Applicability::Unspecified; + } span_lint_and_sugg( cx, MAP_FLATTEN, - expr.span.with_lo(map_span.lo()), + span, format!("called `map(..).flatten()` on `{caller_ty_name}`"), format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), format!("{method_to_use}({closure_snippet})"), From 78225ccca8980e357123ac936655a40e0b0c8b8f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Jan 2025 12:55:09 +0100 Subject: [PATCH 063/189] Add regression test for #8528 --- tests/ui/map_flatten.rs | 12 ++++++++++++ tests/ui/map_flatten.stderr | 11 ++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index 76916d4659197..eafc8b6e81cab 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -55,6 +55,18 @@ fn long_span() { .collect(); } +#[allow(clippy::useless_vec)] +fn no_suggestion_if_comments_present() { + let vec = vec![vec![1, 2, 3]]; + let _ = vec + .iter() + // a lovely comment explaining the code in very detail + .map(|x| x.iter()) + //~^ ERROR: called `map(..).flatten()` on `Iterator` + // the answer to life, the universe and everything could be here + .flatten(); +} + fn main() { long_span(); } diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index a5837b97617db..34bd174d7dde9 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -102,5 +102,14 @@ LL + } LL + }) | -error: aborting due to 4 previous errors +error: called `map(..).flatten()` on `Iterator` + --> tests/ui/map_flatten.rs:64:10 + | +LL | .map(|x| x.iter()) + | __________^ +... | +LL | | .flatten(); + | |__________________^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| x.iter())` + +error: aborting due to 5 previous errors From 63487dde5318bdddbf2fb2d24d725acc99833e88 Mon Sep 17 00:00:00 2001 From: hrxi Date: Thu, 28 Nov 2024 19:34:09 +0100 Subject: [PATCH 064/189] `clippy::redundant_locals` is not a correctness lint Even its documentation says so. According to the documentation, it might either be a "suspicious" or a "perf" lint. --- clippy_lints/src/redundant_locals.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 4f46ca3c71505..658d93e634cf9 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -17,9 +17,9 @@ declare_clippy_lint! { /// Checks for redundant redefinitions of local bindings. /// /// ### Why is this bad? - /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended. + /// Redundant redefinitions of local bindings do not change behavior other than variable's lifetimes and are likely to be unintended. /// - /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation. + /// These rebindings can be intentional to shorten the lifetimes of variables because they affect when the `Drop` implementation is called. Other than that, they do not affect your code's meaning but they _may_ affect `rustc`'s stack allocation. /// /// ### Example /// ```no_run @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.73.0"] pub REDUNDANT_LOCALS, - correctness, + suspicious, "redundant redefinition of a local binding" } declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]); From 85a71ea0c781920a25cc5945f21f72c40334cc77 Mon Sep 17 00:00:00 2001 From: Kornel Date: Mon, 6 Jan 2025 23:39:53 +0000 Subject: [PATCH 065/189] More compelling env_clear() examples --- library/std/src/process.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 929d2b57afe5c..c87d4d01f2950 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -868,13 +868,17 @@ impl Command { /// /// # Examples /// + /// Prevent any inherited `GIT_DIR` variable from changing the target of the `git` command, + /// while allowing all other variables, like `GIT_AUTHOR_NAME`. + /// /// ```no_run /// use std::process::Command; /// - /// Command::new("ls") - /// .env_remove("PATH") - /// .spawn() - /// .expect("ls command failed to start"); + /// Command::new("git") + /// .arg("commit") + /// .env_remove("GIT_DIR") + /// .spawn()?; + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn env_remove>(&mut self, key: K) -> &mut Command { @@ -896,13 +900,17 @@ impl Command { /// /// # Examples /// + /// The behavior of `sort` is affected by `LANG` and `LC_*` environment variables. + /// Clearing the environment makes `sort`'s behavior independent of the parent processes' language. + /// /// ```no_run /// use std::process::Command; /// - /// Command::new("ls") + /// Command::new("sort") + /// .arg("file.txt") /// .env_clear() - /// .spawn() - /// .expect("ls command failed to start"); + /// .spawn()?; + /// # std::io::Result::Ok(()) /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn env_clear(&mut self) -> &mut Command { From aa8d5bff4c0fe9e7c1d50a0827b2c734406c3896 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 12 Dec 2024 01:20:26 -0800 Subject: [PATCH 066/189] cleanup: remove `ExtraConstraintInfo` `ExtraConstraintInfo` was used only for a single subdiagnostic, so this moves the logic for that to its own function and eliminates the indirection. In order to do so cleanly, this also changes the arguments to `BorrowExplanation::add_explanation_to_diagnostic`, which happens to simplify its call sites. --- .../src/diagnostics/conflict_errors.rs | 75 +++---------------- .../src/diagnostics/explain_borrow.rs | 37 +++++---- .../rustc_borrowck/src/diagnostics/mod.rs | 36 ++++++++- .../src/diagnostics/region_errors.rs | 17 ++--- .../rustc_borrowck/src/region_infer/mod.rs | 34 ++------- 5 files changed, 68 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8e5944d6cf45e..2d993a3fd16f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1516,15 +1516,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }); self.explain_why_borrow_contains_point(location, borrow, None) - .add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - Some(borrow_span), - None, - ); + .add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None); self.suggest_copy_for_type_in_cloned_ref(&mut err, place); let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); if let Some(expr) = self.find_expr(borrow_span) { @@ -1591,15 +1583,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }); self.explain_why_borrow_contains_point(location, borrow, None) - .add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); + .add_explanation_to_diagnostic(&self, &mut err, "", None, None); err } @@ -1886,9 +1870,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, + &self, &mut err, first_borrow_desc, None, @@ -3046,15 +3028,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let BorrowExplanation::MustBeValidFor { .. } = explanation { } else { - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); + explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None); } } else { err.span_label(borrow_span, "borrowed value does not live long enough"); @@ -3067,15 +3041,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } }); - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - Some(borrow_span), - None, - ); + explanation.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None); } err @@ -3128,15 +3094,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { _ => {} } - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); + explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None); self.buffer_error(err); } @@ -3309,15 +3267,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } _ => {} } - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); + explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None); borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { @@ -3808,15 +3758,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } }); - self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); + self.explain_why_borrow_contains_point(location, loan, None) + .add_explanation_to_diagnostic(&self, &mut err, "", None, None); self.explain_deref_coercion(loan, &mut err); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 87017460e8ec3..860d6338a0284 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -8,7 +8,6 @@ use std::assert_matches::assert_matches; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; -use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::mir::{ @@ -18,14 +17,15 @@ use rustc_middle::mir::{ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; use rustc_middle::util::CallKind; -use rustc_span::{DesugaringKind, Span, Symbol, kw, sym}; +use rustc_span::{DesugaringKind, Span, kw, sym}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use tracing::{debug, instrument}; use super::{RegionName, UseSpans, find_use}; use crate::borrow_set::BorrowData; +use crate::constraints::OutlivesConstraint; use crate::nll::ConstraintDescription; -use crate::region_infer::{BlameConstraint, Cause, ExtraConstraintInfo}; +use crate::region_infer::{BlameConstraint, Cause}; use crate::{MirBorrowckCtxt, WriteKind}; #[derive(Debug)] @@ -43,7 +43,7 @@ pub(crate) enum BorrowExplanation<'tcx> { span: Span, region_name: RegionName, opt_place_desc: Option, - extra_info: Vec, + path: Vec>, }, Unexplained, } @@ -63,14 +63,16 @@ impl<'tcx> BorrowExplanation<'tcx> { } pub(crate) fn add_explanation_to_diagnostic( &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local_names: &IndexSlice>, + cx: &MirBorrowckCtxt<'_, '_, 'tcx>, err: &mut Diag<'_>, borrow_desc: &str, borrow_span: Option, multiple_borrow_span: Option<(Span, Span)>, ) { + let tcx = cx.infcx.tcx; + let body = cx.body; + let local_names = &cx.local_names; + if let Some(span) = borrow_span { let def_id = body.source.def_id(); if let Some(node) = tcx.hir().get_if_local(def_id) @@ -306,7 +308,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ref region_name, ref opt_place_desc, from_closure: _, - ref extra_info, + ref path, } => { region_name.highlight_region_name(err); @@ -328,13 +330,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ); }; - for extra in extra_info { - match extra { - ExtraConstraintInfo::PlaceholderFromPredicate(span) => { - err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); - } - } - } + cx.add_placeholder_from_predicate_note(err, &path); if let ConstraintCategory::Cast { is_implicit_coercion: true, @@ -487,8 +483,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { &self, borrow_region: RegionVid, outlived_region: RegionVid, - ) -> (ConstraintCategory<'tcx>, bool, Span, Option, Vec) { - let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint( + ) -> (ConstraintCategory<'tcx>, bool, Span, Option, Vec>) + { + let (blame_constraint, path) = self.regioncx.best_blame_constraint( borrow_region, NllRegionVariableOrigin::FreeRegion, |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), @@ -497,7 +494,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let outlived_fr_name = self.give_region_a_name(outlived_region); - (category, from_closure, cause.span, outlived_fr_name, extra_info) + (category, from_closure, cause.span, outlived_fr_name, path) } /// Returns structured explanation for *why* the borrow contains the @@ -596,7 +593,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { None => { if let Some(region) = self.to_error_region_vid(borrow_region_vid) { - let (category, from_closure, span, region_name, extra_info) = + let (category, from_closure, span, region_name, path) = self.free_region_constraint_info(borrow_region_vid, region); if let Some(region_name) = region_name { let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref()); @@ -606,7 +603,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { span, region_name, opt_place_desc, - extra_info, + path, } } else { debug!("Could not generate a region name"); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index ebbdfea302cd3..c9100f23e12e7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -8,14 +8,16 @@ use rustc_errors::{Applicability, Diag, MultiSpan}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; use rustc_index::IndexSlice; -use rustc_infer::infer::BoundRegionConversionTime; +use rustc_infer::infer::{ + BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin, +}; use rustc_infer::traits::SelectionError; use rustc_middle::bug; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, - Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo, + LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, + StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -33,6 +35,7 @@ use tracing::debug; use super::MirBorrowckCtxt; use super::borrow_set::BorrowData; +use crate::constraints::OutlivesConstraint; use crate::fluent_generated as fluent; use crate::session_diagnostics::{ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, @@ -619,6 +622,31 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { region.print(&mut printer).unwrap(); printer.into_buffer() } + + /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates + /// implicitly introduce an "outlives `'static`" constraint. + fn add_placeholder_from_predicate_note( + &self, + err: &mut Diag<'_>, + path: &[OutlivesConstraint<'tcx>], + ) { + let predicate_span = path.iter().find_map(|constraint| { + let outlived = constraint.sub; + if let Some(origin) = self.regioncx.var_infos.get(outlived) + && let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) = + origin.origin + && let ConstraintCategory::Predicate(span) = constraint.category + { + Some(span) + } else { + None + } + }); + + if let Some(span) = predicate_span { + err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); + } + } } /// The span(s) associated to a use of a place. diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 3555009c63f4a..481b8d41f10cd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -29,7 +29,7 @@ use tracing::{debug, instrument, trace}; use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource}; use crate::nll::ConstraintDescription; use crate::region_infer::values::RegionElement; -use crate::region_infer::{BlameConstraint, ExtraConstraintInfo, TypeTest}; +use crate::region_infer::{BlameConstraint, TypeTest}; use crate::session_diagnostics::{ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr, LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote, @@ -440,10 +440,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let (blame_constraint, extra_info) = - self.regioncx.best_blame_constraint(fr, fr_origin, |r| { - self.regioncx.provides_universal_region(r, fr, outlived_fr) - }); + let (blame_constraint, path) = self.regioncx.best_blame_constraint(fr, fr_origin, |r| { + self.regioncx.provides_universal_region(r, fr, outlived_fr) + }); let BlameConstraint { category, cause, variance_info, .. } = blame_constraint; debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); @@ -554,13 +553,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - for extra in extra_info { - match extra { - ExtraConstraintInfo::PlaceholderFromPredicate(span) => { - diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); - } - } - } + self.add_placeholder_from_predicate_note(&mut diag, &path); self.buffer_error(diag); } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2150759d329ea..b49fa463a4f9e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -315,11 +315,6 @@ enum Trace<'tcx> { NotVisited, } -#[derive(Clone, PartialEq, Eq, Debug)] -pub(crate) enum ExtraConstraintInfo { - PlaceholderFromPredicate(Span), -} - #[instrument(skip(infcx, sccs), level = "debug")] fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { use crate::renumber::RegionCtxt; @@ -1948,7 +1943,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { from_region: RegionVid, from_region_origin: NllRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, - ) -> (BlameConstraint<'tcx>, Vec) { + ) -> (BlameConstraint<'tcx>, Vec>) { // Find all paths let (path, target_region) = self .find_constraint_paths_between_regions(from_region, target_test) @@ -1970,25 +1965,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect::>() ); - let mut extra_info = vec![]; - for constraint in path.iter() { - let outlived = constraint.sub; - let Some(origin) = self.var_infos.get(outlived) else { - continue; - }; - let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin - else { - continue; - }; - debug!(?constraint, ?p); - let ConstraintCategory::Predicate(span) = constraint.category else { - continue; - }; - extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span)); - // We only want to point to one - break; - } - // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. // Instead, we use it to produce an improved `ObligationCauseCode`. // FIXME - determine what we should do if we encounter multiple @@ -2115,7 +2091,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let best_choice = if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; - debug!(?best_choice, ?blame_source, ?extra_info); + debug!(?best_choice, ?blame_source); if let Some(i) = best_choice { if let Some(next) = categorized_path.get(i + 1) { @@ -2124,7 +2100,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { { // The return expression is being influenced by the return type being // impl Trait, point at the return type and not the return expr. - return (next.clone(), extra_info); + return (next.clone(), path); } } @@ -2144,7 +2120,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - return (categorized_path[i].clone(), extra_info); + return (categorized_path[i].clone(), path); } // If that search fails, that is.. unusual. Maybe everything @@ -2154,7 +2130,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { categorized_path.sort_by_key(|p| p.category); debug!("sorted_path={:#?}", categorized_path); - (categorized_path.remove(0), extra_info) + (categorized_path.remove(0), path) } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { From 2249232ad8886089221fbd68016dbee0ee2484bc Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 12 Dec 2024 02:00:07 -0800 Subject: [PATCH 067/189] further clean up `best_blame_constraint` This gets rid of `categorized_path`, as it was redundant given the `OutlivesConstraint`s in `path` already have a category field. --- compiler/rustc_borrowck/src/lib.rs | 1 + .../rustc_borrowck/src/region_infer/mod.rs | 95 +++++++++---------- 2 files changed, 46 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index b061a450c83f7..f0eda61d93682 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -6,6 +6,7 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b49fa463a4f9e..058aec58e7876 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1983,18 +1983,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .unwrap_or_else(|| ObligationCauseCode::Misc); - // Classify each of the constraints along the path. - let mut categorized_path: Vec> = path - .iter() - .map(|constraint| BlameConstraint { - category: constraint.category, - from_closure: constraint.from_closure, - cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()), - variance_info: constraint.variance_info, - }) - .collect(); - debug!("categorized_path={:#?}", categorized_path); - // To find the best span to cite, we first try to look for the // final constraint that is interesting and where the `sup` is // not unified with the ultimate target region. The reason @@ -2015,7 +2003,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // we still want to screen for an "interesting" point to // highlight (e.g., a call site or something). let target_scc = self.constraint_sccs.scc(target_region); - let mut range = 0..path.len(); // As noted above, when reporting an error, there is typically a chain of constraints // leading from some "source" region which must outlive some "target" region. @@ -2059,13 +2046,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { | NllRegionVariableOrigin::Existential { from_forall: true } => false, }; - let find_region = |i: &usize| { - let constraint = &path[*i]; - + let interesting_to_blame = |constraint: &OutlivesConstraint<'tcx>| { let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); if blame_source { - match categorized_path[*i].category { + match constraint.category { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation @@ -2078,7 +2063,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } else { !matches!( - categorized_path[*i].category, + constraint.category, ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation @@ -2088,49 +2073,59 @@ impl<'tcx> RegionInferenceContext<'tcx> { } }; - let best_choice = - if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; + let best_choice = if blame_source { + path.iter().rposition(interesting_to_blame) + } else { + path.iter().position(interesting_to_blame) + }; debug!(?best_choice, ?blame_source); - if let Some(i) = best_choice { - if let Some(next) = categorized_path.get(i + 1) { - if matches!(categorized_path[i].category, ConstraintCategory::Return(_)) - && next.category == ConstraintCategory::OpaqueType - { - // The return expression is being influenced by the return type being - // impl Trait, point at the return type and not the return expr. - return (next.clone(), path); - } + let best_constraint = match best_choice { + Some(i) + if let Some(next) = path.get(i + 1) + && matches!(path[i].category, ConstraintCategory::Return(_)) + && next.category == ConstraintCategory::OpaqueType => + { + // The return expression is being influenced by the return type being + // impl Trait, point at the return type and not the return expr. + *next } - if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) + Some(i) + if path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) + && let Some(field) = path.iter().find_map(|p| { + if let ConstraintCategory::ClosureUpvar(f) = p.category { + Some(f) + } else { + None + } + }) => { - let field = categorized_path.iter().find_map(|p| { - if let ConstraintCategory::ClosureUpvar(f) = p.category { - Some(f) - } else { - None - } - }); - - if let Some(field) = field { - categorized_path[i].category = - ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)); + OutlivesConstraint { + category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)), + ..path[i] } } - return (categorized_path[i].clone(), path); - } + Some(i) => path[i], - // If that search fails, that is.. unusual. Maybe everything - // is in the same SCC or something. In that case, find what - // appears to be the most interesting point to report to the - // user via an even more ad-hoc guess. - categorized_path.sort_by_key(|p| p.category); - debug!("sorted_path={:#?}", categorized_path); + None => { + // If that search fails, that is.. unusual. Maybe everything + // is in the same SCC or something. In that case, find what + // appears to be the most interesting point to report to the + // user via an even more ad-hoc guess. + *path.iter().min_by_key(|p| p.category).unwrap() + } + }; - (categorized_path.remove(0), path) + let blame_constraint = BlameConstraint { + category: best_constraint.category, + from_closure: best_constraint.from_closure, + cause: ObligationCause::new(best_constraint.span, CRATE_DEF_ID, cause_code.clone()), + variance_info: best_constraint.variance_info, + }; + (blame_constraint, path) } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { From ac922245f0c86657a56d3ca5eff4a1d1b1fcb0a1 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 4 Dec 2024 03:19:03 -0800 Subject: [PATCH 068/189] `best_blame_constraint`: don't filter constraints by sup SCC The SCCs of the region graph are not a reliable heuristic to use for blaming an interesting constraint for diagnostics. For region errors, if the outlived region is `'static`, or the involved types are invariant in their lifetiems, there will be cycles in the constraint graph containing both the target region and the most interesting constraints to blame. To get better diagnostics in these cases, this commit removes that heuristic. --- .../rustc_borrowck/src/region_infer/mod.rs | 60 +++------------ ...-types-project-from-hrtb-in-fn-body.stderr | 8 +- .../project-fn-ret-invariant.oneuse.stderr | 8 +- ...t-precise-captures-we-are-powerless.stderr | 48 ++++++------ tests/ui/async-await/issue-76547.rs | 4 +- tests/ui/async-await/issue-76547.stderr | 22 +++--- .../borrowck/fn-item-check-type-params.stderr | 4 +- ...ation-not-general-enough-ice-133252.stderr | 8 +- tests/ui/borrowck/issue-7573.rs | 2 + tests/ui/borrowck/issue-7573.stderr | 4 + .../two-phase-surprise-no-conflict.stderr | 22 +++--- tests/ui/c-variadic/variadic-ffi-4.stderr | 6 +- ...-trait-obj-different-regions-lt-ext.stderr | 2 +- ...ptr-to-trait-obj-different-regions-misc.rs | 2 +- ...to-trait-obj-different-regions-misc.stderr | 38 +++++----- tests/ui/coroutine/resume-arg-outlives-2.rs | 2 +- .../ui/coroutine/resume-arg-outlives-2.stderr | 24 +++--- .../dropck/dropck_trait_cycle_checked.stderr | 42 ++++++----- tests/ui/fn/fn_def_coercion.rs | 4 +- tests/ui/fn/fn_def_coercion.stderr | 41 ++++++----- .../precise-capturing/migration-note.rs | 4 +- .../precise-capturing/migration-note.stderr | 16 ++-- .../const-expr-lifetime-err.stderr | 7 +- .../const-match-pat-lifetime-err.stderr | 2 +- tests/ui/issues/issue-15034.stderr | 4 +- .../ui/kindck/kindck-impl-type-params.stderr | 4 +- tests/ui/lifetimes/copy_modulo_regions.stderr | 6 +- .../issue-90170-elision-mismatch.stderr | 9 +++ ...e-90600-expected-return-static-indirect.rs | 2 +- ...600-expected-return-static-indirect.stderr | 28 ++++--- .../ex2b-push-no-existing-names.stderr | 3 + .../ex2c-push-inference-variable.stderr | 3 + .../ex2d-push-inference-variable-2.rs | 2 +- .../ex2d-push-inference-variable-2.stderr | 10 ++- .../ex2e-push-inference-variable-3.rs | 2 +- .../ex2e-push-inference-variable-3.stderr | 10 ++- .../ex3-both-anon-regions-2.rs | 2 +- .../ex3-both-anon-regions-2.stderr | 14 ++-- .../ex3-both-anon-regions-3.stderr | 6 ++ ...both-are-structs-earlybound-regions.stderr | 3 + ...-both-are-structs-latebound-regions.stderr | 3 + ...-both-anon-regions-both-are-structs.stderr | 3 + ...both-anon-regions-latebound-regions.stderr | 3 + ...x3-both-anon-regions-using-fn-items.stderr | 3 + ...-both-anon-regions-using-impl-items.stderr | 3 + ...th-anon-regions-using-trait-objects.stderr | 3 + .../ex3-both-anon-regions.stderr | 3 + .../ui/match/match-ref-mut-invariance.stderr | 4 +- .../ui/match/match-ref-mut-let-invariance.rs | 2 +- .../match/match-ref-mut-let-invariance.stderr | 5 +- ...pagate-approximated-fail-no-postdom.stderr | 4 + .../propagate-approximated-ref.rs | 3 +- .../propagate-approximated-ref.stderr | 20 +++-- ...er-to-static-comparing-against-free.stderr | 12 ++- ...approximated-shorter-to-static-no-bound.rs | 3 +- ...oximated-shorter-to-static-no-bound.stderr | 27 +++---- ...roximated-shorter-to-static-wrong-bound.rs | 3 +- ...mated-shorter-to-static-wrong-bound.stderr | 27 +++---- .../propagate-approximated-val.rs | 3 +- .../propagate-approximated-val.stderr | 20 +++-- ...ail-to-approximate-longer-no-bounds.stderr | 4 + ...-to-approximate-longer-wrong-bounds.stderr | 4 + .../nll/issue-54779-anon-static-lifetime.rs | 2 +- .../issue-54779-anon-static-lifetime.stderr | 14 +++- .../nll/issue-62007-assign-const-index.stderr | 7 +- ...issue-62007-assign-differing-fields.stderr | 7 +- tests/ui/nll/issue-67007-escaping-data.rs | 4 +- tests/ui/nll/issue-67007-escaping-data.stderr | 8 +- tests/ui/nll/issue-95272.rs | 2 +- tests/ui/nll/issue-95272.stderr | 9 ++- .../ui/nll/outlives-suggestion-simple.stderr | 4 + .../assignment-to-differing-field.stderr | 16 ++-- ...insensitive-scopes-issue-117146.nll.stderr | 35 ++++----- ...sitive-scopes-issue-117146.polonius.stderr | 35 ++++----- ...ocation-insensitive-scopes-issue-117146.rs | 4 +- .../nll/relate_tys/var-appears-twice.stderr | 7 +- .../projection-one-region-closure.stderr | 58 ++++++++------- ...tion-one-region-trait-bound-closure.stderr | 14 +++- ...tion-two-region-trait-bound-closure.stderr | 2 +- .../user-annotations/adt-nullary-enums.stderr | 73 +++++++++---------- .../adt-tuple-struct-calls.stderr | 18 ++--- .../nll/user-annotations/method-ufcs-1.stderr | 7 +- .../nll/user-annotations/method-ufcs-2.stderr | 7 +- tests/ui/nll/where_clauses_in_structs.stderr | 4 +- ...er-blame-constraint-for-outlives-static.rs | 13 ++++ ...lame-constraint-for-outlives-static.stderr | 11 +++ ...h-suggestion-regression-test-124563.stderr | 4 + ...region-invariant-static-error-reporting.rs | 6 +- ...on-invariant-static-error-reporting.stderr | 18 ++--- ...t-static-bound-needing-more-suggestions.rs | 2 +- ...atic-bound-needing-more-suggestions.stderr | 25 ++++--- .../ui/traits/coercion-generic-regions.stderr | 6 +- .../trait-object-lifetime-default-note.rs | 3 +- .../trait-object-lifetime-default-note.stderr | 6 +- .../type-checking-test-3.stderr | 4 +- .../type-checking-test-4.stderr | 4 +- ...-argument-types-two-region-pointers.stderr | 4 + ...underscore-lifetime-elison-mismatch.stderr | 3 + .../variance-associated-types2.stderr | 4 +- .../variance-contravariant-arg-object.stderr | 2 +- .../variance-covariant-arg-object.stderr | 2 +- .../variance-invariant-arg-object.stderr | 2 +- 102 files changed, 592 insertions(+), 514 deletions(-) create mode 100644 tests/ui/regions/better-blame-constraint-for-outlives-static.rs create mode 100644 tests/ui/regions/better-blame-constraint-for-outlives-static.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 058aec58e7876..4c2aeace67ed9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1945,7 +1945,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { target_test: impl Fn(RegionVid) -> bool, ) -> (BlameConstraint<'tcx>, Vec>) { // Find all paths - let (path, target_region) = self + let (path, _) = self .find_constraint_paths_between_regions(from_region, target_test) .or_else(|| { self.find_constraint_paths_between_regions(from_region, |r| { @@ -1983,29 +1983,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .unwrap_or_else(|| ObligationCauseCode::Misc); - // To find the best span to cite, we first try to look for the - // final constraint that is interesting and where the `sup` is - // not unified with the ultimate target region. The reason - // for this is that we have a chain of constraints that lead - // from the source to the target region, something like: - // - // '0: '1 ('0 is the source) - // '1: '2 - // '2: '3 - // '3: '4 - // '4: '5 - // '5: '6 ('6 is the target) - // - // Some of those regions are unified with `'6` (in the same - // SCC). We want to screen those out. After that point, the - // "closest" constraint we have to the end is going to be the - // most likely to be the point where the value escapes -- but - // we still want to screen for an "interesting" point to - // highlight (e.g., a call site or something). - let target_scc = self.constraint_sccs.scc(target_region); - - // As noted above, when reporting an error, there is typically a chain of constraints - // leading from some "source" region which must outlive some "target" region. + // When reporting an error, there is typically a chain of constraints leading from some + // "source" region which must outlive some "target" region. // In most cases, we prefer to "blame" the constraints closer to the target -- // but there is one exception. When constraints arise from higher-ranked subtyping, // we generally prefer to blame the source value, @@ -2047,30 +2026,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; let interesting_to_blame = |constraint: &OutlivesConstraint<'tcx>| { - let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); - - if blame_source { - match constraint.category { - ConstraintCategory::OpaqueType + !matches!( + constraint.category, + ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal - | ConstraintCategory::Predicate(_) => false, - ConstraintCategory::TypeAnnotation - | ConstraintCategory::Return(_) - | ConstraintCategory::Yield => true, - _ => constraint_sup_scc != target_scc, - } - } else { - !matches!( - constraint.category, - ConstraintCategory::OpaqueType - | ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal - | ConstraintCategory::Predicate(_) - ) - } + | ConstraintCategory::Predicate(_) + ) }; let best_choice = if blame_source { @@ -2111,10 +2074,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { Some(i) => path[i], None => { - // If that search fails, that is.. unusual. Maybe everything - // is in the same SCC or something. In that case, find what - // appears to be the most interesting point to report to the - // user via an even more ad-hoc guess. + // If that search fails, the only constraints on the path are those that we try not + // to blame. In that case, find what appears to be the most interesting point to + // report to the user via an even more ad-hoc guess. *path.iter().min_by_key(|p| p.category).unwrap() } }; diff --git a/tests/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr b/tests/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr index e12d42e5ed0cc..42d83fca6ca83 100644 --- a/tests/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr +++ b/tests/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.stderr @@ -7,9 +7,9 @@ LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>( | lifetime `'a` defined here ... LL | let z: I::A = if cond { x } else { y }; - | ^ assignment requires that `'a` must outlive `'b` + | ^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` error: lifetime may not live long enough --> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:40 @@ -20,9 +20,9 @@ LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>( | lifetime `'a` defined here ... LL | let z: I::A = if cond { x } else { y }; - | ^ assignment requires that `'b` must outlive `'a` + | ^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` help: `'a` and `'b` must be the same: replace one with the other diff --git a/tests/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr b/tests/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr index 77841780f6216..3ef6b85c407af 100644 --- a/tests/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr +++ b/tests/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr @@ -7,9 +7,9 @@ LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | lifetime `'a` defined here LL | let f = foo; // <-- No consistent type can be inferred for `f` here. LL | let a = bar(f, x); - | ^^^^^^^^^ argument requires that `'a` must outlive `'b` + | ^^^^^^^^^ argument requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant = note: the struct `Type<'a>` is invariant over the parameter `'a` = help: see for more information about variance @@ -23,9 +23,9 @@ LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | lifetime `'a` defined here ... LL | let b = bar(f, y); - | ^^^^^^^^^ argument requires that `'b` must outlive `'a` + | ^^^^^^^^^ argument requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant = note: the struct `Type<'a>` is invariant over the parameter `'a` = help: see for more information about variance diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index be39dbf313bf0..329cec6dad3a3 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -7,7 +7,7 @@ LL | let c = async || { println!("{}", *x); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); - | ------------ argument requires that `x` is borrowed for `'a` + | ---------------------------- argument requires that `x` is borrowed for `'a` ... LL | } | - `x` dropped here while still borrowed @@ -21,10 +21,10 @@ LL | fn simple<'a>(x: &'a i32) { LL | let c = async move || { println!("{}", *x); }; | - binding `c` declared here LL | outlives::<'a>(c()); - | ^-- - | | - | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ---------------^--- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed @@ -38,7 +38,7 @@ LL | let c = async || { println!("{}", *x.0); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); - | ------------ argument requires that `x` is borrowed for `'a` + | ---------------------------- argument requires that `x` is borrowed for `'a` ... LL | } | - `x` dropped here while still borrowed @@ -52,7 +52,7 @@ LL | let c = async || { println!("{}", *x.0); }; | ---------------------------------- borrow of `x` occurs here LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); - | ------------ argument requires that `x` is borrowed for `'a` + | ---------------------------- argument requires that `x` is borrowed for `'a` LL | LL | let c = async move || { println!("{}", *x.0); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `x` occurs here @@ -66,10 +66,10 @@ LL | fn through_field<'a>(x: S<'a>) { LL | let c = async move || { println!("{}", *x.0); }; | - binding `c` declared here LL | outlives::<'a>(c()); - | ^-- - | | - | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ---------------^--- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed @@ -83,10 +83,10 @@ LL | fn through_field<'a>(x: S<'a>) { LL | let c = async move || { println!("{}", *x.0); }; | - binding `c` declared here LL | outlives::<'a>(c()); - | --- - | | - | borrow of `c` occurs here - | argument requires that `c` is borrowed for `'a` + | ------------------- + | | | + | | borrow of `c` occurs here + | argument requires that `c` is borrowed for `'a` LL | outlives::<'a>(call_once(c)); | ^ move out of `c` occurs here @@ -99,18 +99,18 @@ LL | let c = async || { println!("{}", *x.0); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); - | ------------ argument requires that `x` is borrowed for `'a` + | ---------------------------- argument requires that `x` is borrowed for `'a` LL | } | - `x` dropped here while still borrowed error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/without-precise-captures-we-are-powerless.rs:38:20 + --> $DIR/without-precise-captures-we-are-powerless.rs:38:5 | LL | fn through_field_and_ref<'a>(x: &S<'a>) { | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` ... LL | outlives::<'a>(call_once(c)); - | ^^^^^^^^^^^^ lifetime `'a` required + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required error[E0597]: `c` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:43:20 @@ -120,22 +120,22 @@ LL | fn through_field_and_ref_move<'a>(x: &S<'a>) { LL | let c = async move || { println!("{}", *x.0); }; | - binding `c` declared here LL | outlives::<'a>(c()); - | ^-- - | | - | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ---------------^--- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/without-precise-captures-we-are-powerless.rs:44:20 + --> $DIR/without-precise-captures-we-are-powerless.rs:44:5 | LL | fn through_field_and_ref_move<'a>(x: &S<'a>) { | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` ... LL | outlives::<'a>(call_once(c)); - | ^^^^^^^^^^^^ lifetime `'a` required + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required error: aborting due to 10 previous errors diff --git a/tests/ui/async-await/issue-76547.rs b/tests/ui/async-await/issue-76547.rs index 30a39c8943789..24decf9b5f77e 100644 --- a/tests/ui/async-await/issue-76547.rs +++ b/tests/ui/async-await/issue-76547.rs @@ -17,8 +17,8 @@ impl<'a> Future for ListFut<'a> { } async fn fut(bufs: &mut [&mut [u8]]) { - ListFut(bufs).await //~^ ERROR lifetime may not live long enough + ListFut(bufs).await } pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]); @@ -31,8 +31,8 @@ impl<'a> Future for ListFut2<'a> { } async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { - ListFut2(bufs).await //~^ ERROR lifetime may not live long enough + ListFut2(bufs).await } fn main() {} diff --git a/tests/ui/async-await/issue-76547.stderr b/tests/ui/async-await/issue-76547.stderr index 4d96cce824b91..73803a14e7a5e 100644 --- a/tests/ui/async-await/issue-76547.stderr +++ b/tests/ui/async-await/issue-76547.stderr @@ -1,12 +1,11 @@ error: lifetime may not live long enough - --> $DIR/issue-76547.rs:20:13 + --> $DIR/issue-76547.rs:19:14 | LL | async fn fut(bufs: &mut [&mut [u8]]) { - | - - let's call the lifetime of this reference `'2` - | | - | let's call the lifetime of this reference `'1` -LL | ListFut(bufs).await - | ^^^^ this usage requires that `'1` must outlive `'2` + | ^^^^ - - let's call the lifetime of this reference `'2` + | | | + | | let's call the lifetime of this reference `'1` + | assignment requires that `'1` must outlive `'2` | help: consider introducing a named lifetime parameter | @@ -14,14 +13,13 @@ LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/issue-76547.rs:34:14 + --> $DIR/issue-76547.rs:33:15 | LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { - | - - let's call the lifetime of this reference `'2` - | | - | let's call the lifetime of this reference `'1` -LL | ListFut2(bufs).await - | ^^^^ this usage requires that `'1` must outlive `'2` + | ^^^^ - - let's call the lifetime of this reference `'2` + | | | + | | let's call the lifetime of this reference `'1` + | assignment requires that `'1` must outlive `'2` | help: consider introducing a named lifetime parameter | diff --git a/tests/ui/borrowck/fn-item-check-type-params.stderr b/tests/ui/borrowck/fn-item-check-type-params.stderr index 3a29edc55c54f..aafb7e66ef55f 100644 --- a/tests/ui/borrowck/fn-item-check-type-params.stderr +++ b/tests/ui/borrowck/fn-item-check-type-params.stderr @@ -12,12 +12,12 @@ LL | extend_lt(val); | argument requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/fn-item-check-type-params.rs:39:12 + --> $DIR/fn-item-check-type-params.rs:39:31 | LL | pub fn test_coercion<'a>() { | -- lifetime `'a` defined here LL | let _: fn(&'a str) -> _ = extend_lt; - | ^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^ coercion requires that `'a` must outlive `'static` error[E0716]: temporary value dropped while borrowed --> $DIR/fn-item-check-type-params.rs:48:11 diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index 13c768dcbf636..4ec4d2138db60 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -15,10 +15,10 @@ LL | async { LL | let not_static = 0; | ---------- binding `not_static` declared here LL | force_send(async_load(¬_static)); - | -----------^^^^^^^^^^^- - | | | - | | borrowed value does not live long enough - | argument requires that `not_static` is borrowed for `'1` + | ----------------------^^^^^^^^^^^-- + | | | + | | borrowed value does not live long enough + | argument requires that `not_static` is borrowed for `'1` ... LL | } | - `not_static` dropped here while still borrowed diff --git a/tests/ui/borrowck/issue-7573.rs b/tests/ui/borrowck/issue-7573.rs index 7c07411533ff0..f94cd75ab6e2e 100644 --- a/tests/ui/borrowck/issue-7573.rs +++ b/tests/ui/borrowck/issue-7573.rs @@ -17,6 +17,8 @@ pub fn remove_package_from_database() { lines_to_use.push(installed_id); //~^ ERROR borrowed data escapes outside of closure //~| NOTE `installed_id` escapes the closure body here + //~| NOTE requirement occurs because of a mutable reference to `Vec<&CrateId>` + //~| NOTE mutable references are invariant over their type parameter }; list_database(push_id); diff --git a/tests/ui/borrowck/issue-7573.stderr b/tests/ui/borrowck/issue-7573.stderr index 07a67474c8310..d0121f4ec174f 100644 --- a/tests/ui/borrowck/issue-7573.stderr +++ b/tests/ui/borrowck/issue-7573.stderr @@ -9,6 +9,10 @@ LL | let push_id = |installed_id: &CrateId| { LL | LL | lines_to_use.push(installed_id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here + | + = note: requirement occurs because of a mutable reference to `Vec<&CrateId>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr index 89b15a7a659dd..4d1d7ffd29353 100644 --- a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr +++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr @@ -71,14 +71,13 @@ error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as imm LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { | -- lifetime `'a` defined here ... +LL | let reg = mk_reg(); + | -------- assignment requires that `reg.sess_mut` is borrowed for `'a` LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); - | ^^^^^^^^^^^^^^^^^^-----------------------------------------^ - | | | | - | | | immutable borrow occurs here - | | coercion requires that `reg.sess_mut` is borrowed for `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ + | | | + | | immutable borrow occurs here | mutable borrow occurs here - | - = note: due to object lifetime defaults, `Box LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>` error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable --> $DIR/two-phase-surprise-no-conflict.rs:144:5 @@ -115,14 +114,13 @@ error[E0499]: cannot borrow `*reg` as mutable more than once at a time LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { | -- lifetime `'a` defined here ... +LL | let reg = mk_reg(); + | -------- assignment requires that `reg.sess_mut` is borrowed for `'a` LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | ^^^^^^^^^^^^^^^^^^-------------------------------------------------^ - | | | | - | | | first mutable borrow occurs here - | | coercion requires that `reg.sess_mut` is borrowed for `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ + | | | + | | first mutable borrow occurs here | second mutable borrow occurs here - | - = note: due to object lifetime defaults, `Box LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>` error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:158:53 diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index c9d90d73dea31..fc9f8036083a6 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -120,14 +120,14 @@ LL | } | - `ap1` dropped here while still borrowed error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:35:12 + --> $DIR/variadic-ffi-4.rs:35:5 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { | ------- ------- has type `VaListImpl<'2>` | | | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | ^^^^ assignment requires that `'2` must outlive `'1` | = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` @@ -141,7 +141,7 @@ LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut | | | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` + | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` | = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr index b7319e3356bd0..ed9ebce4832c2 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> { | -- lifetime `'a` defined here LL | x as _ - | ^^^^^^ returning this value requires that `'a` must outlive `'static` + | ^^^^^^ cast requires that `'a` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs index 18566acc07fe4..f8910c944c61e 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs @@ -42,7 +42,7 @@ fn change_assoc_1<'a, 'b>( // This tests the default borrow check error, without the special casing for return values. fn require_static(_: *const dyn Trait<'static>) {} fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) { - require_static(ptr as _) //~ error: lifetime may not live long enough + require_static(ptr as _) //~ error: borrowed data escapes outside of function } fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr index 6f590585c4a46..6eeaeb120a729 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr @@ -6,12 +6,9 @@ LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> { | | | lifetime `'a` defined here LL | x as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | ^^^^^^ cast requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>` - = note: mutable pointers are invariant over their type parameter - = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5 @@ -38,12 +35,9 @@ LL | fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> { | | | lifetime `'a` defined here LL | x as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | ^^^^^^ cast requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>` - = note: mutable pointers are invariant over their type parameter - = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:15:5 @@ -91,12 +85,9 @@ LL | fn change_assoc_0<'a, 'b>( | lifetime `'a` defined here ... LL | x as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | ^^^^^^ cast requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a mutable pointer to `dyn Assocked` - = note: mutable pointers are invariant over their type parameter - = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5 @@ -127,12 +118,9 @@ LL | fn change_assoc_1<'a, 'b>( | lifetime `'a` defined here ... LL | x as _ - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | ^^^^^^ cast requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a mutable pointer to `dyn Assocked>` - = note: mutable pointers are invariant over their type parameter - = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5 @@ -154,14 +142,22 @@ help: `'b` and `'a` must be the same: replace one with the other | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:45:20 +error[E0521]: borrowed data escapes outside of function + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:45:5 | LL | fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) { - | -- lifetime `'a` defined here + | -- --- + | | | + | | `ptr` declared here, outside of the function body + | | `ptr` is a reference that is only valid in the function body + | lifetime `'a` defined here LL | require_static(ptr as _) - | ^^^^^^^^ cast requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `ptr` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0521. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/coroutine/resume-arg-outlives-2.rs b/tests/ui/coroutine/resume-arg-outlives-2.rs index 387b143ea279e..a805cea9b7ea4 100644 --- a/tests/ui/coroutine/resume-arg-outlives-2.rs +++ b/tests/ui/coroutine/resume-arg-outlives-2.rs @@ -18,8 +18,8 @@ fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> { // exploit: generator.as_mut().resume(""); generator.as_mut().resume(s); // <- generator hoards it as `let ctx`. - //~^ ERROR borrowed data escapes outside of function thread::spawn(move || { + //~^ ERROR borrowed data escapes outside of function thread::sleep(time::Duration::from_millis(200)); generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`. }) diff --git a/tests/ui/coroutine/resume-arg-outlives-2.stderr b/tests/ui/coroutine/resume-arg-outlives-2.stderr index 3d630d7e7e483..92192d9a55721 100644 --- a/tests/ui/coroutine/resume-arg-outlives-2.stderr +++ b/tests/ui/coroutine/resume-arg-outlives-2.stderr @@ -1,16 +1,20 @@ error[E0521]: borrowed data escapes outside of function - --> $DIR/resume-arg-outlives-2.rs:20:5 + --> $DIR/resume-arg-outlives-2.rs:21:5 | -LL | fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> { - | ----------- - `s` is a reference that is only valid in the function body - | | - | lifetime `'not_static` defined here +LL | fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> { + | ----------- - `s` is a reference that is only valid in the function body + | | + | lifetime `'not_static` defined here ... -LL | generator.as_mut().resume(s); // <- generator hoards it as `let ctx`. - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `s` escapes the function body here - | argument requires that `'not_static` must outlive `'static` +LL | / thread::spawn(move || { +LL | | +LL | | thread::sleep(time::Duration::from_millis(200)); +LL | | generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`. +LL | | }) + | | ^ + | | | + | |______`s` escapes the function body here + | argument requires that `'not_static` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/dropck/dropck_trait_cycle_checked.stderr b/tests/ui/dropck/dropck_trait_cycle_checked.stderr index f32736f1a674c..e595e98fa2e43 100644 --- a/tests/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/tests/ui/dropck/dropck_trait_cycle_checked.stderr @@ -2,83 +2,87 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:111:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here LL | o1.set0(&o2); | ^^^ borrowed value does not live long enough ... +LL | o3.set0(&o1); + | ------------ argument requires that `o2` is borrowed for `'static` +LL | o3.set1(&o2); LL | } | - `o2` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o3` declared here -------- coercion requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here LL | o1.set0(&o2); LL | o1.set1(&o3); | ^^^ borrowed value does not live long enough ... +LL | o3.set0(&o1); + | ------------ argument requires that `o3` is borrowed for `'static` +LL | o3.set1(&o2); LL | } | - `o3` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:113:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` -... + | -- binding `o2` declared here +LL | o1.set0(&o2); + | ------------ argument requires that `o2` is borrowed for `'static` +LL | o1.set1(&o3); LL | o2.set0(&o2); | ^^^ borrowed value does not live long enough ... LL | } | - `o2` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o3` declared here -------- coercion requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here +LL | o1.set0(&o2); + | ------------ argument requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough ... LL | } | - `o3` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o1` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:115:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o1` declared here -------- coercion requires that `o1` is borrowed for `'static` + | -- binding `o1` declared here +LL | o1.set0(&o2); +LL | o1.set1(&o3); + | ------------ argument requires that `o1` is borrowed for `'static` ... LL | o3.set0(&o1); | ^^^ borrowed value does not live long enough LL | o3.set1(&o2); LL | } | - `o1` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here +LL | o1.set0(&o2); +LL | o1.set1(&o3); + | ------------ argument requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough LL | } | - `o2` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error: aborting due to 6 previous errors diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs index 313be6f28cdcc..31c8fa41de17c 100644 --- a/tests/ui/fn/fn_def_coercion.rs +++ b/tests/ui/fn/fn_def_coercion.rs @@ -46,12 +46,12 @@ fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { let x = match true { - true => foo::<&'c ()>, + true => foo::<&'c ()>, //~ ERROR lifetime may not live long enough false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough }; x(a); - x(b); //~ ERROR lifetime may not live long enough + x(b); x(c); } diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr index ec4a1bde7fd61..c2776887b79d4 100644 --- a/tests/ui/fn/fn_def_coercion.stderr +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -6,9 +6,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | | | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -22,9 +22,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -53,9 +53,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'c ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -69,9 +69,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | x = foo::<&'a ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -89,9 +89,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let x = match true { LL | true => foo::<&'b ()>, - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -105,9 +105,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -117,15 +117,15 @@ help: `'a` and `'b` must be the same: replace one with the other = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:50:18 + --> $DIR/fn_def_coercion.rs:49:17 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'c` defined here | | | lifetime `'a` defined here -... -LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` +LL | let x = match true { +LL | true => foo::<&'c ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` | = help: consider adding the following bound: `'a: 'c` = note: requirement occurs because of a function pointer to `foo` @@ -133,17 +133,20 @@ LL | false => foo::<&'a ()>, = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:54:5 + --> $DIR/fn_def_coercion.rs:50:18 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | x(b); - | ^^^^ argument requires that `'b` must outlive `'a` +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance help: the following changes may resolve your lifetime errors | diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs index 36db07e5764f5..7587e89409aaa 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.rs +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -29,11 +29,11 @@ fn needs_static() { let a = display_len(&x); //~^ ERROR `x` does not live long enough //~| NOTE this call may capture more lifetimes than intended - //~| NOTE argument requires that `x` is borrowed for `'static` //~| NOTE borrowed value does not live long enoug fn needs_static(_: impl Sized + 'static) {} needs_static(a); + //~^ NOTE argument requires that `x` is borrowed for `'static` } //~^ NOTE `x` dropped here while still borrowed @@ -76,11 +76,11 @@ fn needs_static_mut() { let a = display_len_mut(&mut x); //~^ ERROR `x` does not live long enough //~| NOTE this call may capture more lifetimes than intended - //~| NOTE argument requires that `x` is borrowed for `'static` //~| NOTE borrowed value does not live long enough fn needs_static(_: impl Sized + 'static) {} needs_static(a); + //~^ NOTE argument requires that `x` is borrowed for `'static` } //~^ NOTE `x` dropped here while still borrowed diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr index c9403532dfa35..9caf7a201ef8a 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -42,11 +42,11 @@ LL | let x = vec![1]; | - binding `x` declared here LL | LL | let a = display_len(&x); - | ------------^^- - | | | - | | borrowed value does not live long enough - | argument requires that `x` is borrowed for `'static` + | ^^ borrowed value does not live long enough ... +LL | needs_static(a); + | --------------- argument requires that `x` is borrowed for `'static` +LL | LL | } | - `x` dropped here while still borrowed | @@ -118,11 +118,11 @@ LL | let mut x = vec![1]; | ----- binding `x` declared here LL | LL | let a = display_len_mut(&mut x); - | ----------------^^^^^^- - | | | - | | borrowed value does not live long enough - | argument requires that `x` is borrowed for `'static` + | ^^^^^^ borrowed value does not live long enough ... +LL | needs_static(a); + | --------------- argument requires that `x` is borrowed for `'static` +LL | LL | } | - `x` dropped here while still borrowed | diff --git a/tests/ui/inline-const/const-expr-lifetime-err.stderr b/tests/ui/inline-const/const-expr-lifetime-err.stderr index be3fc8d28c51e..031bf98262a87 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.stderr +++ b/tests/ui/inline-const/const-expr-lifetime-err.stderr @@ -6,10 +6,9 @@ LL | fn foo<'a>() { LL | let y = (); | - binding `y` declared here LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW }); - | ------------------^^- - | | | - | | borrowed value does not live long enough - | argument requires that `y` is borrowed for `'a` + | ^^ ----------------------- using this value as a constant requires that `y` is borrowed for `'a` + | | + | borrowed value does not live long enough LL | LL | } | - `y` dropped here while still borrowed diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr index 95fe7085e5027..7eea1846057af 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr @@ -9,7 +9,7 @@ LL | match InvariantRef::new(&y) { | ^^ borrowed value does not live long enough LL | LL | const { InvariantRef::<'a>::NEW } => (), - | --------------------------------- type annotation requires that `y` is borrowed for `'a` + | ----------------------- using this value as a constant requires that `y` is borrowed for `'a` LL | } LL | } | - `y` dropped here while still borrowed diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/issues/issue-15034.stderr index 587a5c85e924a..c5bc31f94d981 100644 --- a/tests/ui/issues/issue-15034.stderr +++ b/tests/ui/issues/issue-15034.stderr @@ -1,10 +1,10 @@ error[E0621]: explicit lifetime required in the type of `lexer` - --> $DIR/issue-15034.rs:17:9 + --> $DIR/issue-15034.rs:17:25 | LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> { | ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>` LL | Parser { lexer: lexer } - | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | ^^^^^ lifetime `'a` required error: aborting due to 1 previous error diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index a0a4ef09216f6..d375aa9cb5961 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -112,13 +112,13 @@ LL | struct Foo; // does not impl Copy | error: lifetime may not live long enough - --> $DIR/kindck-impl-type-params.rs:30:19 + --> $DIR/kindck-impl-type-params.rs:30:13 | LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let t: S<&'a isize> = S(marker::PhantomData); LL | let a = &t as &dyn Gettable<&'a isize>; - | ^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static` error: aborting due to 7 previous errors diff --git a/tests/ui/lifetimes/copy_modulo_regions.stderr b/tests/ui/lifetimes/copy_modulo_regions.stderr index 310ddb21647f6..920fec09103b2 100644 --- a/tests/ui/lifetimes/copy_modulo_regions.stderr +++ b/tests/ui/lifetimes/copy_modulo_regions.stderr @@ -4,11 +4,7 @@ error: lifetime may not live long enough LL | fn foo<'a>() -> [Foo<'a>; 100] { | -- lifetime `'a` defined here LL | [mk_foo::<'a>(); 100] - | ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant - = note: the struct `Foo<'a>` is invariant over the parameter `'a` - = help: see for more information about variance + | ^^^^^^^^^^^^^^^^^^^^^ copying this value requires that `'a` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr b/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr index 82511d07b0efc..5e16c57a618ff 100644 --- a/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr +++ b/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr @@ -7,6 +7,9 @@ LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } @@ -21,6 +24,9 @@ LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } @@ -35,6 +41,9 @@ LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider reusing a named lifetime parameter | LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.rs b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.rs index ce4cddc9b39b3..30a1811fee547 100644 --- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.rs +++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.rs @@ -7,9 +7,9 @@ fn inner(mut foo: &[u8]) { let refcell = RefCell::new(&mut foo); //~^ ERROR `foo` does not live long enough let read = &refcell as &RefCell; - //~^ ERROR lifetime may not live long enough read_thing(read); + //~^ ERROR borrowed data escapes outside of function } fn read_thing(refcell: &RefCell) {} diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index e4cd54ac33741..4df2e906e222f 100644 --- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -5,22 +5,32 @@ LL | fn inner(mut foo: &[u8]) { | ------- binding `foo` declared here LL | let refcell = RefCell::new(&mut foo); | ^^^^^^^^ borrowed value does not live long enough -LL | -LL | let read = &refcell as &RefCell; - | ------------------------------ cast requires that `foo` is borrowed for `'static` ... +LL | read_thing(read); + | ---------------- argument requires that `foo` is borrowed for `'static` +LL | LL | } | - `foo` dropped here while still borrowed -error: lifetime may not live long enough - --> $DIR/issue-90600-expected-return-static-indirect.rs:9:16 +error[E0521]: borrowed data escapes outside of function + --> $DIR/issue-90600-expected-return-static-indirect.rs:11:5 | LL | fn inner(mut foo: &[u8]) { - | - let's call the lifetime of this reference `'1` + | ------- - let's call the lifetime of this reference `'1` + | | + | `foo` is a reference that is only valid in the function body ... -LL | let read = &refcell as &RefCell; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static` +LL | read_thing(read); + | ^^^^^^^^^^^^^^^^ + | | + | `foo` escapes the function body here + | argument requires that `'1` must outlive `'static` + | + = note: requirement occurs because of the type `RefCell<(dyn std::io::Read + 'static)>`, which makes the generic argument `(dyn std::io::Read + 'static)` invariant + = note: the struct `RefCell` is invariant over the parameter `T` + = help: see for more information about variance error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0521, E0597. +For more information about an error, try `rustc --explain E0521`. diff --git a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr index 6f7127d4c4c4e..a187cb755dd56 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -8,6 +8,9 @@ LL | fn foo(x: &mut Vec>, y: Ref) { LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(x: &mut Vec>, y: Ref<'a, i32>) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr b/tests/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr index cace80272f5b5..610a669cdedd3 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.stderr @@ -10,6 +10,9 @@ LL | x.push(z); | ^^^^^^^^^ argument requires that `'c` must outlive `'b` | = help: consider adding the following bound: `'c: 'b` + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.rs b/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.rs index f573230293eef..4cd06e1c02b2a 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.rs @@ -4,9 +4,9 @@ struct Ref<'a, T: 'a> { fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { let a: &mut Vec> = x; + //~^ ERROR lifetime may not live long enough let b = Ref { data: y.data }; a.push(b); - //~^ ERROR lifetime may not live long enough } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr index 4a981e4de604d..0da32aacdb3d4 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.stderr @@ -1,15 +1,17 @@ error: lifetime may not live long enough - --> $DIR/ex2d-push-inference-variable-2.rs:8:5 + --> $DIR/ex2d-push-inference-variable-2.rs:6:33 | LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { | -- -- lifetime `'c` defined here | | | lifetime `'b` defined here -... -LL | a.push(b); - | ^^^^^^^^^ argument requires that `'c` must outlive `'b` +LL | let a: &mut Vec> = x; + | ^ assignment requires that `'c` must outlive `'b` | = help: consider adding the following bound: `'c: 'b` + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.rs b/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.rs index 4a934bbf080d5..498cea3682473 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.rs @@ -4,9 +4,9 @@ struct Ref<'a, T: 'a> { fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { let a: &mut Vec> = x; + //~^ ERROR lifetime may not live long enough let b = Ref { data: y.data }; Vec::push(a, b); - //~^ ERROR lifetime may not live long enough } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr index 2bd047113bca0..4474a898fdc65 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.stderr @@ -1,15 +1,17 @@ error: lifetime may not live long enough - --> $DIR/ex2e-push-inference-variable-3.rs:8:5 + --> $DIR/ex2e-push-inference-variable-3.rs:6:33 | LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { | -- -- lifetime `'c` defined here | | | lifetime `'b` defined here -... -LL | Vec::push(a, b); - | ^^^^^^^^^^^^^^^ argument requires that `'c` must outlive `'b` +LL | let a: &mut Vec> = x; + | ^ assignment requires that `'c` must outlive `'b` | = help: consider adding the following bound: `'c: 'b` + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs index 09ee9accccd2f..66e6eb91a22e3 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs @@ -1,6 +1,6 @@ fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - *v = x; //~^ ERROR lifetime may not live long enough + *v = x; } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr index 30083b5ef5462..e7cab52084ddd 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -1,13 +1,15 @@ error: lifetime may not live long enough - --> $DIR/ex3-both-anon-regions-2.rs:2:5 + --> $DIR/ex3-both-anon-regions-2.rs:1:14 | LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - | - - let's call the lifetime of this reference `'1` - | | - | let's call the lifetime of this reference `'2` -LL | *v = x; - | ^^^^^^ assignment requires that `'1` must outlive `'2` + | ^^^^^^^^^ - - let's call the lifetime of this reference `'1` + | | | + | | let's call the lifetime of this reference `'2` + | assignment requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `&u8` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr index 6ba130308a33a..c67ea19effc07 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr @@ -8,6 +8,9 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { LL | z.push((x,y)); | ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec<(&u8, &u8)>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) { @@ -23,6 +26,9 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { LL | z.push((x,y)); | ^^^^^^^^^^^^^ argument requires that `'3` must outlive `'4` | + = note: requirement occurs because of a mutable reference to `Vec<(&u8, &u8)>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr index 352619c0ffc3f..0980b37e535a1 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.stderr @@ -10,6 +10,9 @@ LL | x.push(y); | ^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr index 16cf009ee48bc..16cd47420a58e 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.stderr @@ -9,6 +9,9 @@ LL | x.push(y); | ^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr index 017bfa7146317..264673ff3e82c 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr @@ -8,6 +8,9 @@ LL | fn foo(mut x: Vec, y: Ref) { LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(mut x: Vec>, y: Ref<'a>) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr index 080eb43cecbc4..8552755d16852 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.stderr @@ -9,6 +9,9 @@ LL | x.push(y); | ^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr index cb629d2e3d3fc..2a2cf6508fdb7 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr @@ -19,6 +19,9 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr index 420cfa6b569b6..01bfe7829206d 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.stderr @@ -8,6 +8,9 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) { LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter and update trait if needed | LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr index 05f9308124b1e..41154755b5d88 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr @@ -19,6 +19,9 @@ LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(x:Box , y: Vec<&'a u8>, z: &'a u8) { diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr index 875d22576e58c..10e8ca852f0f7 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr @@ -8,6 +8,9 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) { LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { diff --git a/tests/ui/match/match-ref-mut-invariance.stderr b/tests/ui/match/match-ref-mut-invariance.stderr index b9878a1953242..93844d34b414b 100644 --- a/tests/ui/match/match-ref-mut-invariance.stderr +++ b/tests/ui/match/match-ref-mut-invariance.stderr @@ -1,12 +1,12 @@ error: lifetime may not live long enough - --> $DIR/match-ref-mut-invariance.rs:10:9 + --> $DIR/match-ref-mut-invariance.rs:10:24 | LL | impl<'b> S<'b> { | -- lifetime `'b` defined here LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | match self.0 { ref mut x => x } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | ^^^^^^^^^ assignment requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` diff --git a/tests/ui/match/match-ref-mut-let-invariance.rs b/tests/ui/match/match-ref-mut-let-invariance.rs index a33be09ac8be2..2c1f865b6d750 100644 --- a/tests/ui/match/match-ref-mut-let-invariance.rs +++ b/tests/ui/match/match-ref-mut-let-invariance.rs @@ -8,8 +8,8 @@ struct S<'b>(&'b i32); impl<'b> S<'b> { fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { let ref mut x = self.0; - x //~^ ERROR lifetime may not live long enough + x } } diff --git a/tests/ui/match/match-ref-mut-let-invariance.stderr b/tests/ui/match/match-ref-mut-let-invariance.stderr index 27968239a8e54..3c5d73bb4f724 100644 --- a/tests/ui/match/match-ref-mut-let-invariance.stderr +++ b/tests/ui/match/match-ref-mut-let-invariance.stderr @@ -1,13 +1,12 @@ error: lifetime may not live long enough - --> $DIR/match-ref-mut-let-invariance.rs:11:9 + --> $DIR/match-ref-mut-let-invariance.rs:10:13 | LL | impl<'b> S<'b> { | -- lifetime `'b` defined here LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | let ref mut x = self.0; -LL | x - | ^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | ^^^^^^^^^ assignment requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index f37ce967a1ba3..60087ec992bd6 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -23,6 +23,10 @@ LL | |_outlives1, _outlives2, _outlives3, x, y| { ... LL | demand_y(x, y, p) | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type `Cell<&'?34 u32>`, which makes the generic argument `&'?34 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance note: no external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:38:1 diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs b/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs index 1c27e38f83214..f4db723704cb8 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs @@ -41,9 +41,10 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { + //~^ ERROR lifetime may not live long enough + // Only works if 'x: 'y: demand_y(x, y, x.get()) - //~^ ERROR lifetime may not live long enough }); } diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr index e2d0b105ab14d..7325a9de8b294 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -23,17 +23,21 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { = note: defining type: supply error: lifetime may not live long enough - --> $DIR/propagate-approximated-ref.rs:45:9 + --> $DIR/propagate-approximated-ref.rs:43:5 | -LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | demand_y(x, y, x.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b` +LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { +... | +LL | | }); + | |______^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type `Cell<&'?11 u32>`, which makes the generic argument `&'?11 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index d7933a39eaacf..0094d7a50d369 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -19,6 +19,10 @@ LL | foo(cell, |cell_a, cell_x| { | `cell_a` declared here, outside of the closure body LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here + | + = note: requirement occurs because of the type `Cell<&'?8 u32>`, which makes the generic argument `&'?8 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance note: no external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:18:1 @@ -56,11 +60,11 @@ error[E0597]: `a` does not live long enough LL | let a = 0; | - binding `a` declared here LL | let cell = Cell::new(&a); - | ----------^^- - | | | - | | borrowed value does not live long enough - | argument requires that `a` is borrowed for `'static` + | ^^ borrowed value does not live long enough ... +LL | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error + | ------------------------ argument requires that `a` is borrowed for `'static` +LL | }) LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs index 25e212a722568..afabb69ec4cd0 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs @@ -30,10 +30,9 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - //~^ ERROR borrowed data escapes outside of function - // Only works if 'x: 'y: demand_y(x, y, x.get()) + //~^ ERROR borrowed data escapes outside of function }); } diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 3c04cf300ad43..b9365c94a1bed 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -23,23 +23,18 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { = note: defining type: supply error[E0521]: borrowed data escapes outside of function - --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5 + --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:34:9 | -LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | -- ------ `cell_a` is a reference that is only valid in the function body - | | - | lifetime `'a` defined here -LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { -... | -LL | | }); - | | ^ - | | | - | |______`cell_a` escapes the function body here - | argument requires that `'a` must outlive `'static` - | - = note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant - = note: the struct `Cell` is invariant over the parameter `T` - = help: see for more information about variance +LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +... +LL | demand_y(x, y, x.get()) + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs index cda7b22362f3e..9f3e80d3db669 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs @@ -33,10 +33,9 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3 #[rustc_regions] fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - //~^ ERROR borrowed data escapes outside of function - // Only works if 'x: 'y: demand_y(x, y, x.get()) + //~^ ERROR borrowed data escapes outside of function }); } diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 9f5762ccbfa68..e5d2867103cfc 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -23,23 +23,18 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { = note: defining type: supply error[E0521]: borrowed data escapes outside of function - --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5 + --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:37:9 | -LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | -- ------ `cell_a` is a reference that is only valid in the function body - | | - | lifetime `'a` defined here -LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { -... | -LL | | }); - | | ^ - | | | - | |______`cell_a` escapes the function body here - | argument requires that `'a` must outlive `'static` - | - = note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant - = note: the struct `Cell` is invariant over the parameter `T` - = help: see for more information about variance +LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +... +LL | demand_y(x, y, x.get()) + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.rs b/tests/ui/nll/closure-requirements/propagate-approximated-val.rs index e7e2f157604be..4d663c53d27a1 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-val.rs +++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.rs @@ -34,9 +34,10 @@ fn demand_y<'x, 'y>(_outlives1: Cell<&&'x u32>, _outlives2: Cell<&'y &u32>, _y: #[rustc_regions] fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { + //~^ ERROR lifetime may not live long enough + // Only works if 'x: 'y: demand_y(outlives1, outlives2, x.get()) - //~^ ERROR lifetime may not live long enough }); } diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr index 4787577a6e1a6..a14bfb06e831e 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -23,17 +23,21 @@ LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { = note: defining type: test error: lifetime may not live long enough - --> $DIR/propagate-approximated-val.rs:38:9 + --> $DIR/propagate-approximated-val.rs:36:5 | -LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | demand_y(outlives1, outlives2, x.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b` +LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { +... | +LL | | }); + | |______^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type `Cell<&'?7 u32>`, which makes the generic argument `&'?7 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 669b56a0be70c..4558ff50674f8 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -22,6 +22,10 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type `Cell<&'?37 u32>`, which makes the generic argument `&'?37 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance note: no external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:34:1 diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 75f476ac5f188..83173ae80c00d 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -22,6 +22,10 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type `Cell<&'?43 u32>`, which makes the generic argument `&'?43 u32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance note: no external requirements --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:38:1 diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.rs b/tests/ui/nll/issue-54779-anon-static-lifetime.rs index 260b6b109ca9b..3a92b9709a1d3 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.rs +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.rs @@ -29,7 +29,7 @@ impl DebugWith for Foo { fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { let Foo { bar } = self; - bar.debug_with(cx); //~ ERROR: lifetime may not live long enough + bar.debug_with(cx); //~ ERROR borrowed data escapes outside of method [E0521] Ok(()) } } diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr index a454ed265685c..03a5590661422 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr @@ -1,11 +1,17 @@ -error: lifetime may not live long enough - --> $DIR/issue-54779-anon-static-lifetime.rs:32:24 +error[E0521]: borrowed data escapes outside of method + --> $DIR/issue-54779-anon-static-lifetime.rs:32:9 | LL | cx: &dyn DebugContext, - | - let's call the lifetime of this reference `'1` + | -- - let's call the lifetime of this reference `'1` + | | + | `cx` is a reference that is only valid in the method body ... LL | bar.debug_with(cx); - | ^^ coercion requires that `'1` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^ + | | + | `cx` escapes the method body here + | argument requires that `'1` must outlive `'static` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/nll/issue-62007-assign-const-index.stderr b/tests/ui/nll/issue-62007-assign-const-index.stderr index 0db9fe62c3869..32716c47cd4d8 100644 --- a/tests/ui/nll/issue-62007-assign-const-index.stderr +++ b/tests/ui/nll/issue-62007-assign-const-index.stderr @@ -17,10 +17,9 @@ LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { | - let's call the lifetime of this reference `'1` ... LL | if let Some(n) = list[0].next.as_mut() { - | ^^^^^^^^^^^^--------- - | | - | `list[_].next` was mutably borrowed here in the previous iteration of the loop - | argument requires that `list[_].next` is borrowed for `'1` + | ^^^^^^^^^^^^ `list[_].next` was mutably borrowed here in the previous iteration of the loop +LL | list[0] = n; + | ----------- assignment requires that `list[_].next` is borrowed for `'1` error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-62007-assign-differing-fields.stderr b/tests/ui/nll/issue-62007-assign-differing-fields.stderr index f1af2e855afe6..d51fd7a1389a0 100644 --- a/tests/ui/nll/issue-62007-assign-differing-fields.stderr +++ b/tests/ui/nll/issue-62007-assign-differing-fields.stderr @@ -17,10 +17,9 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a | -- lifetime `'a` defined here ... LL | if let Some(n) = (list.0).next.as_mut() { - | ^^^^^^^^^^^^^--------- - | | - | `list.0.next` was mutably borrowed here in the previous iteration of the loop - | argument requires that `list.0.next` is borrowed for `'a` + | ^^^^^^^^^^^^^ `list.0.next` was mutably borrowed here in the previous iteration of the loop +LL | list.1 = n; + | ---------- assignment requires that `list.0.next` is borrowed for `'a` error: aborting due to 2 previous errors diff --git a/tests/ui/nll/issue-67007-escaping-data.rs b/tests/ui/nll/issue-67007-escaping-data.rs index 49ea2e5964fa2..92a47f7884308 100644 --- a/tests/ui/nll/issue-67007-escaping-data.rs +++ b/tests/ui/nll/issue-67007-escaping-data.rs @@ -12,8 +12,8 @@ struct Consumer<'tcx>(&'tcx ()); impl<'tcx> Consumer<'tcx> { fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { - let other = self.use_fcx(fcx); //~ ERROR lifetime may not live long enough - fcx.use_it(other); + let other = self.use_fcx(fcx); + fcx.use_it(other); //~ ERROR lifetime may not live long enough } fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () { diff --git a/tests/ui/nll/issue-67007-escaping-data.stderr b/tests/ui/nll/issue-67007-escaping-data.stderr index eb7b57c7e998a..3b9ed24685180 100644 --- a/tests/ui/nll/issue-67007-escaping-data.stderr +++ b/tests/ui/nll/issue-67007-escaping-data.stderr @@ -1,14 +1,18 @@ error: lifetime may not live long enough - --> $DIR/issue-67007-escaping-data.rs:15:21 + --> $DIR/issue-67007-escaping-data.rs:16:9 | LL | impl<'tcx> Consumer<'tcx> { | ---- lifetime `'tcx` defined here LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { | -- lifetime `'a` defined here LL | let other = self.use_fcx(fcx); - | ^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'tcx` +LL | fcx.use_it(other); + | ^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'tcx` | = help: consider adding the following bound: `'a: 'tcx` + = note: requirement occurs because of the type `FnCtxt<'_, '_>`, which makes the generic argument `'_` invariant + = note: the struct `FnCtxt<'a, 'tcx>` is invariant over the parameter `'tcx` + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-95272.rs b/tests/ui/nll/issue-95272.rs index 958cbde37882d..b3325a05e5c07 100644 --- a/tests/ui/nll/issue-95272.rs +++ b/tests/ui/nll/issue-95272.rs @@ -8,8 +8,8 @@ where fn test<'a, 'b>(x: Cell<&'a ()>, y: Cell<&'b ()>) { let f = check; - //~^ ERROR lifetime may not live long enough f(x, y); + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/tests/ui/nll/issue-95272.stderr b/tests/ui/nll/issue-95272.stderr index 0453ef8e53ea3..3d1720239e9a0 100644 --- a/tests/ui/nll/issue-95272.stderr +++ b/tests/ui/nll/issue-95272.stderr @@ -1,16 +1,17 @@ error: lifetime may not live long enough - --> $DIR/issue-95272.rs:10:13 + --> $DIR/issue-95272.rs:11:5 | LL | fn test<'a, 'b>(x: Cell<&'a ()>, y: Cell<&'b ()>) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | let f = check; - | ^^^^^ assignment requires that `'a` must outlive `'b` +LL | f(x, y); + | ^^^^^^^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` - = note: requirement occurs because of a function pointer to `check` - = note: the function `check` is invariant over the parameter `'a` + = note: requirement occurs because of the type `Cell<&()>`, which makes the generic argument `&()` invariant + = note: the struct `Cell` is invariant over the parameter `T` = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/nll/outlives-suggestion-simple.stderr b/tests/ui/nll/outlives-suggestion-simple.stderr index bcffd575aed48..669532005b292 100644 --- a/tests/ui/nll/outlives-suggestion-simple.stderr +++ b/tests/ui/nll/outlives-suggestion-simple.stderr @@ -99,6 +99,10 @@ LL | fn get_bar(&self) -> Bar2 { | - let's call the lifetime of this reference `'1` LL | Bar2::new(&self) | ^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a` + | + = note: requirement occurs because of the type `Foo2<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Foo2<'a>` is invariant over the parameter `'a` + = help: see for more information about variance error: aborting due to 9 previous errors diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.stderr b/tests/ui/nll/polonius/assignment-to-differing-field.stderr index acac47eac4f0e..c46d010e4f576 100644 --- a/tests/ui/nll/polonius/assignment-to-differing-field.stderr +++ b/tests/ui/nll/polonius/assignment-to-differing-field.stderr @@ -17,10 +17,10 @@ LL | fn assignment_to_field_projection<'a, T>( | -- lifetime `'a` defined here ... LL | if let Some(n) = (list.0).next.as_mut() { - | ^^^^^^^^^^^^^--------- - | | - | `list.0.next` was mutably borrowed here in the previous iteration of the loop - | argument requires that `list.0.next` is borrowed for `'a` + | ^^^^^^^^^^^^^ `list.0.next` was mutably borrowed here in the previous iteration of the loop +LL | +LL | list.1 = n; + | ---------- assignment requires that `list.0.next` is borrowed for `'a` error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time --> $DIR/assignment-to-differing-field.rs:37:21 @@ -41,10 +41,10 @@ LL | fn assignment_through_projection_chain<'a, T>( | -- lifetime `'a` defined here ... LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- - | | - | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop - | argument requires that `list.0.0.0.0.0.next` is borrowed for `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop +LL | +LL | *((((list.0).0).0).0).1 = n; + | --------------------------- assignment requires that `list.0.0.0.0.0.next` is borrowed for `'a` error: aborting due to 4 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 1d086c658dfcd..e4b323bc2b6ac 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -1,23 +1,20 @@ -error[E0597]: `a` does not live long enough - --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 +error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function + --> $DIR/location-insensitive-scopes-issue-117146.rs:10:13 | -LL | let a = (); - | - binding `a` declared here LL | let b = |_| &a; - | --- -^ - | | || - | | |borrowed value does not live long enough - | | returning this value requires that `a` is borrowed for `'static` - | value captured here -... -LL | } - | - `a` dropped here while still borrowed - | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 - | -LL | fn bad &()>(_: F) {} - | ^^^ + | ^^^ - `a` is borrowed here + | | + | may outlive borrowed value `a` + | +note: function requires argument type to outlive `'static` + --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 + | +LL | bad(&b); + | ^^^^^^^ +help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword + | +LL | let b = move |_| &a; + | ++++ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -39,4 +36,4 @@ LL | bad(&b); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 1d086c658dfcd..e4b323bc2b6ac 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -1,23 +1,20 @@ -error[E0597]: `a` does not live long enough - --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 +error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function + --> $DIR/location-insensitive-scopes-issue-117146.rs:10:13 | -LL | let a = (); - | - binding `a` declared here LL | let b = |_| &a; - | --- -^ - | | || - | | |borrowed value does not live long enough - | | returning this value requires that `a` is borrowed for `'static` - | value captured here -... -LL | } - | - `a` dropped here while still borrowed - | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 - | -LL | fn bad &()>(_: F) {} - | ^^^ + | ^^^ - `a` is borrowed here + | | + | may outlive borrowed value `a` + | +note: function requires argument type to outlive `'static` + --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 + | +LL | bad(&b); + | ^^^^^^^ +help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword + | +LL | let b = move |_| &a; + | ++++ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -39,4 +36,4 @@ LL | bad(&b); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs index c828a37521e0e..bd26af5bee25c 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs @@ -8,8 +8,8 @@ fn main() { let a = (); let b = |_| &a; - //[nll]~^ ERROR `a` does not live long enough - //[polonius]~^^ ERROR `a` does not live long enough + //[nll]~^ ERROR closure may outlive the current function, but it borrows `a` + //[polonius]~^^ ERROR closure may outlive the current function, but it borrows `a` bad(&b); //[nll]~^ ERROR implementation of `Fn` //[nll]~| ERROR implementation of `FnOnce` diff --git a/tests/ui/nll/relate_tys/var-appears-twice.stderr b/tests/ui/nll/relate_tys/var-appears-twice.stderr index 3f9a6cec0d2e5..2b2ec88ba8e07 100644 --- a/tests/ui/nll/relate_tys/var-appears-twice.stderr +++ b/tests/ui/nll/relate_tys/var-appears-twice.stderr @@ -5,9 +5,10 @@ LL | let b = 44; | - binding `b` declared here ... LL | let x: DoubleCell<_> = make_cell(&b); - | ------------- ^^ borrowed value does not live long enough - | | - | type annotation requires that `b` is borrowed for `'static` + | ----------^^- + | | | + | | borrowed value does not live long enough + | assignment requires that `b` is borrowed for `'static` ... LL | } | - `b` dropped here while still borrowed diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr index dda60398198e7..408c57a31eea8 100644 --- a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -24,6 +24,22 @@ LL | | T: Anything<'b>, | = note: defining type: no_relationships_late::<'?1, T> +error: lifetime may not live long enough + --> $DIR/projection-one-region-closure.rs:45:5 + | +LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Cell<&'?6 ()>`, which makes the generic argument `&'?6 ()` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance + error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:45:39 | @@ -38,19 +54,6 @@ help: consider adding an explicit lifetime bound LL | T: Anything<'b> + 'a, | ++++ -error: lifetime may not live long enough - --> $DIR/projection-one-region-closure.rs:45:39 - | -LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - note: external requirements --> $DIR/projection-one-region-closure.rs:56:29 | @@ -77,6 +80,22 @@ LL | | 'a: 'a, | = note: defining type: no_relationships_early::<'?1, '?2, T> +error: lifetime may not live long enough + --> $DIR/projection-one-region-closure.rs:56:5 + | +LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Cell<&'?7 ()>`, which makes the generic argument `&'?7 ()` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance + error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:56:39 | @@ -91,19 +110,6 @@ help: consider adding an explicit lifetime bound LL | T: Anything<'b> + 'a, | ++++ -error: lifetime may not live long enough - --> $DIR/projection-one-region-closure.rs:56:39 - | -LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -... -LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` - | - = help: consider adding the following bound: `'b: 'a` - note: external requirements --> $DIR/projection-one-region-closure.rs:70:29 | diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 52040663e005c..4ebdf10c5bf3d 100644 --- a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -24,7 +24,7 @@ LL | | T: Anything<'b>, = note: defining type: no_relationships_late::<'?1, T> error: lifetime may not live long enough - --> $DIR/projection-one-region-trait-bound-closure.rs:37:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:37:5 | LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) | -- -- lifetime `'b` defined here @@ -32,9 +32,12 @@ LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) | lifetime `'a` defined here ... LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Cell<&'?6 ()>`, which makes the generic argument `&'?6 ()` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:47:29 @@ -62,7 +65,7 @@ LL | | 'a: 'a, = note: defining type: no_relationships_early::<'?1, '?2, T> error: lifetime may not live long enough - --> $DIR/projection-one-region-trait-bound-closure.rs:47:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:5 | LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) | -- -- lifetime `'b` defined here @@ -70,9 +73,12 @@ LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) | lifetime `'a` defined here ... LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Cell<&'?7 ()>`, which makes the generic argument `&'?7 ()` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:60:29 diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index c157e89ff8f31..f8dbe08af6166 100644 --- a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -182,7 +182,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of the type `Cell<&'?8 ()>`, which makes the generic argument `&'?8 ()` invariant + = note: requirement occurs because of the type `Cell<&'?6 ()>`, which makes the generic argument `&'?6 ()` invariant = note: the struct `Cell` is invariant over the parameter `T` = help: see for more information about variance diff --git a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr index 644fc94f73087..cdaa934122ce0 100644 --- a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr +++ b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr @@ -1,52 +1,49 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-nullary-enums.rs:33:41 | -LL | let c = 66; - | - binding `c` declared here -LL | combine( -LL | SomeEnum::SomeVariant(Cell::new(&c)), - | ----------^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'static` -... -LL | } - | - `c` dropped here while still borrowed +LL | let c = 66; + | - binding `c` declared here +LL | / combine( +LL | | SomeEnum::SomeVariant(Cell::new(&c)), + | | ^^ borrowed value does not live long enough +LL | | SomeEnum::SomeOtherVariant::>, +LL | | ); + | |_____- argument requires that `c` is borrowed for `'static` +LL | } + | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough --> $DIR/adt-nullary-enums.rs:41:41 | -LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { - | -- lifetime `'a` defined here -LL | let c = 66; - | - binding `c` declared here -LL | combine( -LL | SomeEnum::SomeVariant(Cell::new(&c)), - | ----------^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` -... -LL | } - | - `c` dropped here while still borrowed +LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { + | -- lifetime `'a` defined here +LL | let c = 66; + | - binding `c` declared here +LL | / combine( +LL | | SomeEnum::SomeVariant(Cell::new(&c)), + | | ^^ borrowed value does not live long enough +LL | | SomeEnum::SomeOtherVariant::>, +LL | | ); + | |_____- argument requires that `c` is borrowed for `'a` +LL | } + | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough --> $DIR/adt-nullary-enums.rs:54:45 | -LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { - | -- lifetime `'a` defined here -LL | let _closure = || { -LL | let c = 66; - | - binding `c` declared here -LL | combine( -LL | SomeEnum::SomeVariant(Cell::new(&c)), - | ----------^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` -... -LL | }; - | - `c` dropped here while still borrowed +LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { + | -- lifetime `'a` defined here +LL | let _closure = || { +LL | let c = 66; + | - binding `c` declared here +LL | / combine( +LL | | SomeEnum::SomeVariant(Cell::new(&c)), + | | ^^ borrowed value does not live long enough +LL | | SomeEnum::SomeOtherVariant::>, +LL | | ); + | |_________- argument requires that `c` is borrowed for `'a` +LL | }; + | - `c` dropped here while still borrowed error: aborting due to 3 previous errors diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr index 2084697e7e26d..1478ad1431ba4 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -4,11 +4,9 @@ error[E0597]: `c` does not live long enough LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'static u32>; + | -------------------------- assignment requires that `c` is borrowed for `'static` LL | f(&c); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'static` + | ^^ borrowed value does not live long enough LL | } | - `c` dropped here while still borrowed @@ -20,11 +18,9 @@ LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; + | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ^^ borrowed value does not live long enough LL | } | - `c` dropped here while still borrowed @@ -37,11 +33,9 @@ LL | let _closure = || { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; + | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ^^ borrowed value does not live long enough LL | }; | - `c` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index c42ea0172cf75..087e270c70f7d 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -4,11 +4,10 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... +LL | let x = <&'static u32 as Bazoom<_>>::method; + | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | --^^------- - | | | - | | borrowed value does not live long enough - | argument requires that `a` is borrowed for `'static` + | ^^ borrowed value does not live long enough LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index 287337c7d52d3..c89bed3b1b18f 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -4,11 +4,10 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... +LL | let x = <&'static u32 as Bazoom<_>>::method; + | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | --^^------- - | | | - | | borrowed value does not live long enough - | argument requires that `a` is borrowed for `'static` + | ^^ borrowed value does not live long enough LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/where_clauses_in_structs.stderr b/tests/ui/nll/where_clauses_in_structs.stderr index 4cc7e5ab1b4c7..19a1ce00e9a8f 100644 --- a/tests/ui/nll/where_clauses_in_structs.stderr +++ b/tests/ui/nll/where_clauses_in_structs.stderr @@ -1,12 +1,12 @@ error: lifetime may not live long enough - --> $DIR/where_clauses_in_structs.rs:11:11 + --> $DIR/where_clauses_in_structs.rs:11:14 | LL | fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | Foo { x, y }; - | ^ this usage requires that `'a` must outlive `'b` + | ^ this usage requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of the type `Cell<&u32>`, which makes the generic argument `&u32` invariant diff --git a/tests/ui/regions/better-blame-constraint-for-outlives-static.rs b/tests/ui/regions/better-blame-constraint-for-outlives-static.rs new file mode 100644 index 0000000000000..77cadb783016c --- /dev/null +++ b/tests/ui/regions/better-blame-constraint-for-outlives-static.rs @@ -0,0 +1,13 @@ +//! diagnostic test for #132749: ensure we pick a decent span and reason to blame for region errors +//! when failing to prove a region outlives 'static + +struct Bytes(&'static [u8]); + +fn deserialize_simple_string(buf: &[u8]) -> (Bytes, &[u8]) { + //~^ NOTE let's call the lifetime of this reference `'1` + let (s, rest) = buf.split_at(2); + (Bytes(s), rest) //~ ERROR lifetime may not live long enough + //~| NOTE this usage requires that `'1` must outlive `'static` +} + +fn main() {} diff --git a/tests/ui/regions/better-blame-constraint-for-outlives-static.stderr b/tests/ui/regions/better-blame-constraint-for-outlives-static.stderr new file mode 100644 index 0000000000000..e1e88829f2c4f --- /dev/null +++ b/tests/ui/regions/better-blame-constraint-for-outlives-static.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/better-blame-constraint-for-outlives-static.rs:9:12 + | +LL | fn deserialize_simple_string(buf: &[u8]) -> (Bytes, &[u8]) { + | - let's call the lifetime of this reference `'1` +... +LL | (Bytes(s), rest) + | ^ this usage requires that `'1` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr b/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr index fcd0a232a7bd3..9f1315070eb29 100644 --- a/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr +++ b/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr @@ -25,6 +25,10 @@ LL | self.enter_scope(|ctx| { | has type `&mut FooImpl<'2, '_, T>` LL | BarImpl(ctx); | ^^^ this usage requires that `'1` must outlive `'2` + | + = note: requirement occurs because of a mutable reference to `FooImpl<'_, '_, T>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance error: lifetime may not live long enough --> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:22:9 diff --git a/tests/ui/regions/region-invariant-static-error-reporting.rs b/tests/ui/regions/region-invariant-static-error-reporting.rs index 9ab46a7757897..e58eea3f61ae7 100644 --- a/tests/ui/regions/region-invariant-static-error-reporting.rs +++ b/tests/ui/regions/region-invariant-static-error-reporting.rs @@ -3,7 +3,7 @@ // over time, but this test used to exhibit some pretty bogus messages // that were not remotely helpful. -//@ error-pattern:argument requires that `'a` must outlive `'static` +//@ error-pattern:requires that `'a` must outlive `'static` struct Invariant<'a>(Option<&'a mut &'a mut ()>); @@ -11,9 +11,9 @@ fn mk_static() -> Invariant<'static> { Invariant(None) } fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { let bad = if x.is_some() { - x.unwrap() //~ ERROR borrowed data escapes outside of function [E0521] + x.unwrap() } else { - mk_static() + mk_static() //~ ERROR lifetime may not live long enough }; f(bad); } diff --git a/tests/ui/regions/region-invariant-static-error-reporting.stderr b/tests/ui/regions/region-invariant-static-error-reporting.stderr index 834d5c6cf5a8b..2ccf36713ae89 100644 --- a/tests/ui/regions/region-invariant-static-error-reporting.stderr +++ b/tests/ui/regions/region-invariant-static-error-reporting.stderr @@ -1,16 +1,11 @@ -error[E0521]: borrowed data escapes outside of function - --> $DIR/region-invariant-static-error-reporting.rs:14:9 +error: lifetime may not live long enough + --> $DIR/region-invariant-static-error-reporting.rs:16:9 | LL | fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { - | -- - `x` is a reference that is only valid in the function body - | | - | lifetime `'a` defined here -LL | let bad = if x.is_some() { -LL | x.unwrap() - | ^^^^^^^^^^ - | | - | `x` escapes the function body here - | argument requires that `'a` must outlive `'static` + | -- lifetime `'a` defined here +... +LL | mk_static() + | ^^^^^^^^^^^ assignment requires that `'a` must outlive `'static` | = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant = note: the struct `Invariant<'a>` is invariant over the parameter `'a` @@ -18,4 +13,3 @@ LL | x.unwrap() error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs index c24672816acdb..8f3171222bb6f 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs @@ -64,7 +64,7 @@ mod bay { fn use_it<'a>(val: Box + 'a>) -> &'a () { val.use_self() - //~^ ERROR: cannot return value referencing function parameter `val` + //~^ ERROR: `val` does not live long enough //~| ERROR: borrowed data escapes outside of function } } diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 505765d2b41f6..a8a854220b4e5 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -25,6 +25,20 @@ LL | val.use_self() | returns a value referencing data owned by the current function | `val` is borrowed here +error[E0597]: `val` does not live long enough + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9 + | +LL | fn use_it<'a>(val: Box + 'a>) -> &'a () { + | --- binding `val` declared here +LL | val.use_self() + | ^^^----------- + | | + | borrowed value does not live long enough + | argument requires that `val` is borrowed for `'static` +... +LL | } + | - `val` dropped here while still borrowed + error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9 | @@ -50,15 +64,6 @@ help: consider relaxing the implicit `'static` requirement LL | impl MyTrait for Box + '_> { | ++++ -error[E0515]: cannot return value referencing function parameter `val` - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9 - | -LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here - error[E0515]: cannot return value referencing function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:90:9 | @@ -70,5 +75,5 @@ LL | val.use_self() error: aborting due to 6 previous errors -Some errors have detailed explanations: E0515, E0521. +Some errors have detailed explanations: E0515, E0521, E0597. For more information about an error, try `rustc --explain E0515`. diff --git a/tests/ui/traits/coercion-generic-regions.stderr b/tests/ui/traits/coercion-generic-regions.stderr index 576035f8c13e4..c48767095dffb 100644 --- a/tests/ui/traits/coercion-generic-regions.stderr +++ b/tests/ui/traits/coercion-generic-regions.stderr @@ -4,11 +4,9 @@ error[E0597]: `person` does not live long enough LL | let person = "Fred".to_string(); | ------ binding `person` declared here LL | let person: &str = &person; - | ^^^^^^^ - | | - | borrowed value does not live long enough - | assignment requires that `person` is borrowed for `'static` + | ^^^^^^^ borrowed value does not live long enough LL | let s: Box> = Box::new(Struct { person: person }); + | ------ this usage requires that `person` is borrowed for `'static` LL | } | - `person` dropped here while still borrowed diff --git a/tests/ui/traits/trait-object-lifetime-default-note.rs b/tests/ui/traits/trait-object-lifetime-default-note.rs index 275411ff61c85..5d8d2c5391918 100644 --- a/tests/ui/traits/trait-object-lifetime-default-note.rs +++ b/tests/ui/traits/trait-object-lifetime-default-note.rs @@ -6,9 +6,8 @@ fn main() { let local = 0; //~ NOTE binding `local` declared here let r = &local; //~ ERROR `local` does not live long enough //~| NOTE borrowed value does not live long enough - //~| NOTE due to object lifetime defaults, `Box` actually means `Box<(dyn A + 'static)>` require_box(Box::new(r)); - //~^ NOTE coercion requires that `local` is borrowed for `'static` + //~^ NOTE argument requires that `local` is borrowed for `'static` let _ = 0; } //~ NOTE `local` dropped here while still borrowed diff --git a/tests/ui/traits/trait-object-lifetime-default-note.stderr b/tests/ui/traits/trait-object-lifetime-default-note.stderr index 8cb9bc0d80072..9a97704f49371 100644 --- a/tests/ui/traits/trait-object-lifetime-default-note.stderr +++ b/tests/ui/traits/trait-object-lifetime-default-note.stderr @@ -5,14 +5,12 @@ LL | let local = 0; | ----- binding `local` declared here LL | let r = &local; | ^^^^^^ borrowed value does not live long enough -... +LL | LL | require_box(Box::new(r)); - | ----------- coercion requires that `local` is borrowed for `'static` + | ------------------------ argument requires that `local` is borrowed for `'static` ... LL | } | - `local` dropped here while still borrowed - | - = note: due to object lifetime defaults, `Box` actually means `Box<(dyn A + 'static)>` error: aborting due to 1 previous error diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr index 0a969b611e9d3..01b8da645f31a 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr @@ -1,10 +1,10 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:11:18 + --> $DIR/type-checking-test-3.rs:11:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'a>; // Error - | ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/type-checking-test-3.rs:16:18 diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr index 090120a2327a8..e91ea193a0104 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -1,10 +1,10 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:19:18 + --> $DIR/type-checking-test-4.rs:19:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here LL | let _ = x as &dyn Bar<'static, 'a>; // Error - | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'a` must outlive `'static` error: lifetime may not live long enough --> $DIR/type-checking-test-4.rs:24:18 diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr index 40d3414024553..e2f48f37f0dad 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.stderr @@ -7,6 +7,10 @@ LL | doit(0, &|x, y| { | has type `&Cell<&'2 i32>` LL | x.set(y); | ^^^^^^^^ argument requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type `Cell<&i32>`, which makes the generic argument `&i32` invariant + = note: the struct `Cell` is invariant over the parameter `T` + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr index ed9d22d255839..8bd9b1112c56a 100644 --- a/tests/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr +++ b/tests/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr @@ -7,6 +7,9 @@ LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` | + = note: requirement occurs because of a mutable reference to `Vec<&u8>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } diff --git a/tests/ui/variance/variance-associated-types2.stderr b/tests/ui/variance/variance-associated-types2.stderr index 158b09b0630ca..292d60941b185 100644 --- a/tests/ui/variance/variance-associated-types2.stderr +++ b/tests/ui/variance/variance-associated-types2.stderr @@ -1,10 +1,10 @@ error: lifetime may not live long enough - --> $DIR/variance-associated-types2.rs:13:12 + --> $DIR/variance-associated-types2.rs:13:42 | LL | fn take<'a>(_: &'a u32) { | -- lifetime `'a` defined here LL | let _: Box> = make(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | ^^^^^^ coercion requires that `'a` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/variance/variance-contravariant-arg-object.stderr b/tests/ui/variance/variance-contravariant-arg-object.stderr index ab28315e11e52..7d7c6cb28cdf0 100644 --- a/tests/ui/variance/variance-contravariant-arg-object.stderr +++ b/tests/ui/variance/variance-contravariant-arg-object.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box>) | lifetime `'min` defined here ... LL | v - | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | ^ coercion requires that `'min` must outlive `'max` | = help: consider adding the following bound: `'min: 'max` diff --git a/tests/ui/variance/variance-covariant-arg-object.stderr b/tests/ui/variance/variance-covariant-arg-object.stderr index 51f8cb3ec750b..4e82c8e8e1b4b 100644 --- a/tests/ui/variance/variance-covariant-arg-object.stderr +++ b/tests/ui/variance/variance-covariant-arg-object.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box>) | lifetime `'min` defined here ... LL | v - | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | ^ coercion requires that `'min` must outlive `'max` | = help: consider adding the following bound: `'min: 'max` diff --git a/tests/ui/variance/variance-invariant-arg-object.stderr b/tests/ui/variance/variance-invariant-arg-object.stderr index 9793a36be06ab..e3969ebebcea4 100644 --- a/tests/ui/variance/variance-invariant-arg-object.stderr +++ b/tests/ui/variance/variance-invariant-arg-object.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box>) | lifetime `'min` defined here ... LL | v - | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | ^ coercion requires that `'min` must outlive `'max` | = help: consider adding the following bound: `'min: 'max` From 2864906fce4e9252eddb96f2d09e9e2f113a9d4b Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 12 Dec 2024 08:45:32 -0800 Subject: [PATCH 069/189] `best_blame_constraint`: add a special case to recover object lifetime default notes --- .../rustc_borrowck/src/region_infer/mod.rs | 22 +++++++++- .../dropck/dropck_trait_cycle_checked.stderr | 42 +++++++++---------- .../nll/issue-54779-anon-static-lifetime.rs | 2 +- .../issue-54779-anon-static-lifetime.stderr | 14 ++----- .../trait-object-lifetime-default-note.rs | 3 +- .../trait-object-lifetime-default-note.stderr | 6 ++- 6 files changed, 51 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 4c2aeace67ed9..7ec692d36b168 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1945,7 +1945,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { target_test: impl Fn(RegionVid) -> bool, ) -> (BlameConstraint<'tcx>, Vec>) { // Find all paths - let (path, _) = self + let (path, target_region) = self .find_constraint_paths_between_regions(from_region, target_test) .or_else(|| { self.find_constraint_paths_between_regions(from_region, |r| { @@ -2071,6 +2071,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + Some(_) + if target_region == self.universal_regions().fr_static + && let Some(old_best) = path.iter().min_by_key(|p| p.category) + && matches!(old_best.category, ConstraintCategory::Cast { + is_implicit_coercion: true, + unsize_to: Some(_) + }) => + { + // FIXME(dianne): This is a hack in order to emit the subdiagnostic + // `BorrowExplanation::add_object_lifetime_default_note` more often, e.g. on + // `tests/ui/traits/trait-object-lifetime-default-note.rs`. The subdiagnostic + // depends on a coercion being blamed, so we fall back to an earlier version of this + // function's blaming logic to keep the test result the same. A proper fix will + // require rewriting the subdiagnostic not to rely on a coercion being blamed. + // For examples of where notes are missing, see #131008 and + // `tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs`. + // As part of fixing those, this case should be removed. + *old_best + } + Some(i) => path[i], None => { diff --git a/tests/ui/dropck/dropck_trait_cycle_checked.stderr b/tests/ui/dropck/dropck_trait_cycle_checked.stderr index e595e98fa2e43..f32736f1a674c 100644 --- a/tests/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/tests/ui/dropck/dropck_trait_cycle_checked.stderr @@ -2,87 +2,83 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:111:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here + | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` LL | o1.set0(&o2); | ^^^ borrowed value does not live long enough ... -LL | o3.set0(&o1); - | ------------ argument requires that `o2` is borrowed for `'static` -LL | o3.set1(&o2); LL | } | - `o2` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o3` declared here + | -- binding `o3` declared here -------- coercion requires that `o3` is borrowed for `'static` LL | o1.set0(&o2); LL | o1.set1(&o3); | ^^^ borrowed value does not live long enough ... -LL | o3.set0(&o1); - | ------------ argument requires that `o3` is borrowed for `'static` -LL | o3.set1(&o2); LL | } | - `o3` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:113:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -LL | o1.set0(&o2); - | ------------ argument requires that `o2` is borrowed for `'static` -LL | o1.set1(&o3); + | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` +... LL | o2.set0(&o2); | ^^^ borrowed value does not live long enough ... LL | } | - `o2` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o3` declared here -LL | o1.set0(&o2); - | ------------ argument requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here -------- coercion requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough ... LL | } | - `o3` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o1` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:115:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o1` declared here -LL | o1.set0(&o2); -LL | o1.set1(&o3); - | ------------ argument requires that `o1` is borrowed for `'static` + | -- binding `o1` declared here -------- coercion requires that `o1` is borrowed for `'static` ... LL | o3.set0(&o1); | ^^^ borrowed value does not live long enough LL | o3.set1(&o2); LL | } | - `o1` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -- binding `o2` declared here -LL | o1.set0(&o2); -LL | o1.set1(&o3); - | ------------ argument requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- coercion requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough LL | } | - `o2` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box>` actually means `Box<(dyn Obj<'_> + 'static)>` error: aborting due to 6 previous errors diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.rs b/tests/ui/nll/issue-54779-anon-static-lifetime.rs index 3a92b9709a1d3..1dab7c1712afe 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.rs +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.rs @@ -29,7 +29,7 @@ impl DebugWith for Foo { fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { let Foo { bar } = self; - bar.debug_with(cx); //~ ERROR borrowed data escapes outside of method [E0521] + bar.debug_with(cx); //~ lifetime may not live long enough Ok(()) } } diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr index 03a5590661422..a454ed265685c 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr @@ -1,17 +1,11 @@ -error[E0521]: borrowed data escapes outside of method - --> $DIR/issue-54779-anon-static-lifetime.rs:32:9 +error: lifetime may not live long enough + --> $DIR/issue-54779-anon-static-lifetime.rs:32:24 | LL | cx: &dyn DebugContext, - | -- - let's call the lifetime of this reference `'1` - | | - | `cx` is a reference that is only valid in the method body + | - let's call the lifetime of this reference `'1` ... LL | bar.debug_with(cx); - | ^^^^^^^^^^^^^^^^^^ - | | - | `cx` escapes the method body here - | argument requires that `'1` must outlive `'static` + | ^^ coercion requires that `'1` must outlive `'static` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/traits/trait-object-lifetime-default-note.rs b/tests/ui/traits/trait-object-lifetime-default-note.rs index 5d8d2c5391918..275411ff61c85 100644 --- a/tests/ui/traits/trait-object-lifetime-default-note.rs +++ b/tests/ui/traits/trait-object-lifetime-default-note.rs @@ -6,8 +6,9 @@ fn main() { let local = 0; //~ NOTE binding `local` declared here let r = &local; //~ ERROR `local` does not live long enough //~| NOTE borrowed value does not live long enough + //~| NOTE due to object lifetime defaults, `Box` actually means `Box<(dyn A + 'static)>` require_box(Box::new(r)); - //~^ NOTE argument requires that `local` is borrowed for `'static` + //~^ NOTE coercion requires that `local` is borrowed for `'static` let _ = 0; } //~ NOTE `local` dropped here while still borrowed diff --git a/tests/ui/traits/trait-object-lifetime-default-note.stderr b/tests/ui/traits/trait-object-lifetime-default-note.stderr index 9a97704f49371..8cb9bc0d80072 100644 --- a/tests/ui/traits/trait-object-lifetime-default-note.stderr +++ b/tests/ui/traits/trait-object-lifetime-default-note.stderr @@ -5,12 +5,14 @@ LL | let local = 0; | ----- binding `local` declared here LL | let r = &local; | ^^^^^^ borrowed value does not live long enough -LL | +... LL | require_box(Box::new(r)); - | ------------------------ argument requires that `local` is borrowed for `'static` + | ----------- coercion requires that `local` is borrowed for `'static` ... LL | } | - `local` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box` actually means `Box<(dyn A + 'static)>` error: aborting due to 1 previous error From 31e4d8175a3ef5d10f2319e98a20ca6c81614487 Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 13 Dec 2024 08:04:15 -0800 Subject: [PATCH 070/189] `best_blame_constraint`: avoid blaming constraints from MIR generated by desugaring --- .../rustc_borrowck/src/region_infer/mod.rs | 9 +++++++- tests/ui/async-await/issue-76547.rs | 4 ++-- tests/ui/async-await/issue-76547.stderr | 22 ++++++++++--------- tests/ui/async-await/issues/issue-63388-1.rs | 2 +- .../async-await/issues/issue-63388-1.stderr | 15 +++++-------- tests/ui/async-await/issues/issue-63388-2.rs | 2 +- .../async-await/issues/issue-63388-2.stderr | 15 +++++-------- 7 files changed, 36 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 7ec692d36b168..4ceb2fcd8d703 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex}; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; +use rustc_span::hygiene::DesugaringKind; use tracing::{debug, instrument, trace}; use crate::BorrowckInferCtxt; @@ -2033,7 +2034,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal | ConstraintCategory::Predicate(_) - ) + ) && constraint.span.desugaring_kind().is_none_or(|kind| { + // Try to avoid blaming constraints from desugarings, since they may not clearly + // clearly match what users have written. As an exception, allow blaming returns + // generated by `?` desugaring, since the correspondence is fairly clear. + kind == DesugaringKind::QuestionMark + && matches!(constraint.category, ConstraintCategory::Return(_)) + }) }; let best_choice = if blame_source { diff --git a/tests/ui/async-await/issue-76547.rs b/tests/ui/async-await/issue-76547.rs index 24decf9b5f77e..30a39c8943789 100644 --- a/tests/ui/async-await/issue-76547.rs +++ b/tests/ui/async-await/issue-76547.rs @@ -17,8 +17,8 @@ impl<'a> Future for ListFut<'a> { } async fn fut(bufs: &mut [&mut [u8]]) { - //~^ ERROR lifetime may not live long enough ListFut(bufs).await + //~^ ERROR lifetime may not live long enough } pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]); @@ -31,8 +31,8 @@ impl<'a> Future for ListFut2<'a> { } async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { - //~^ ERROR lifetime may not live long enough ListFut2(bufs).await + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/tests/ui/async-await/issue-76547.stderr b/tests/ui/async-await/issue-76547.stderr index 73803a14e7a5e..4d96cce824b91 100644 --- a/tests/ui/async-await/issue-76547.stderr +++ b/tests/ui/async-await/issue-76547.stderr @@ -1,11 +1,12 @@ error: lifetime may not live long enough - --> $DIR/issue-76547.rs:19:14 + --> $DIR/issue-76547.rs:20:13 | LL | async fn fut(bufs: &mut [&mut [u8]]) { - | ^^^^ - - let's call the lifetime of this reference `'2` - | | | - | | let's call the lifetime of this reference `'1` - | assignment requires that `'1` must outlive `'2` + | - - let's call the lifetime of this reference `'2` + | | + | let's call the lifetime of this reference `'1` +LL | ListFut(bufs).await + | ^^^^ this usage requires that `'1` must outlive `'2` | help: consider introducing a named lifetime parameter | @@ -13,13 +14,14 @@ LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/issue-76547.rs:33:15 + --> $DIR/issue-76547.rs:34:14 | LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 { - | ^^^^ - - let's call the lifetime of this reference `'2` - | | | - | | let's call the lifetime of this reference `'1` - | assignment requires that `'1` must outlive `'2` + | - - let's call the lifetime of this reference `'2` + | | + | let's call the lifetime of this reference `'1` +LL | ListFut2(bufs).await + | ^^^^ this usage requires that `'1` must outlive `'2` | help: consider introducing a named lifetime parameter | diff --git a/tests/ui/async-await/issues/issue-63388-1.rs b/tests/ui/async-await/issues/issue-63388-1.rs index a6f499ba94e29..acfc64baff97d 100644 --- a/tests/ui/async-await/issues/issue-63388-1.rs +++ b/tests/ui/async-await/issues/issue-63388-1.rs @@ -11,8 +11,8 @@ impl Xyz { &'a self, foo: &dyn Foo ) -> &dyn Foo //~ WARNING elided lifetime has a name { - //~^ ERROR explicit lifetime required in the type of `foo` [E0621] foo + //~^ ERROR explicit lifetime required in the type of `foo` [E0621] } } diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr index ef74bfe32375e..579caa45bc945 100644 --- a/tests/ui/async-await/issues/issue-63388-1.stderr +++ b/tests/ui/async-await/issues/issue-63388-1.stderr @@ -10,16 +10,13 @@ LL | ) -> &dyn Foo = note: `#[warn(elided_named_lifetimes)]` on by default error[E0621]: explicit lifetime required in the type of `foo` - --> $DIR/issue-63388-1.rs:13:5 + --> $DIR/issue-63388-1.rs:14:9 | -LL | &'a self, foo: &dyn Foo - | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` -LL | ) -> &dyn Foo -LL | / { -LL | | -LL | | foo -LL | | } - | |_____^ lifetime `'a` required +LL | &'a self, foo: &dyn Foo + | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` +... +LL | foo + | ^^^ lifetime `'a` required error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/async-await/issues/issue-63388-2.rs b/tests/ui/async-await/issues/issue-63388-2.rs index 85718f4112151..8bb5cfa4a594a 100644 --- a/tests/ui/async-await/issues/issue-63388-2.rs +++ b/tests/ui/async-await/issues/issue-63388-2.rs @@ -11,8 +11,8 @@ impl Xyz { foo: &dyn Foo, bar: &'a dyn Foo ) -> &dyn Foo //~ ERROR missing lifetime specifier { - //~^ ERROR explicit lifetime required in the type of `foo` [E0621] foo + //~^ ERROR explicit lifetime required in the type of `foo` [E0621] } } diff --git a/tests/ui/async-await/issues/issue-63388-2.stderr b/tests/ui/async-await/issues/issue-63388-2.stderr index e515f227c7ef6..7e3c0a1227de8 100644 --- a/tests/ui/async-await/issues/issue-63388-2.stderr +++ b/tests/ui/async-await/issues/issue-63388-2.stderr @@ -13,16 +13,13 @@ LL | ) -> &'a dyn Foo | ++ error[E0621]: explicit lifetime required in the type of `foo` - --> $DIR/issue-63388-2.rs:13:5 + --> $DIR/issue-63388-2.rs:14:9 | -LL | foo: &dyn Foo, bar: &'a dyn Foo - | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` -LL | ) -> &dyn Foo -LL | / { -LL | | -LL | | foo -LL | | } - | |_____^ lifetime `'a` required +LL | foo: &dyn Foo, bar: &'a dyn Foo + | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` +... +LL | foo + | ^^^ lifetime `'a` required error: aborting due to 2 previous errors From 50222dba2edd2bcf265a8ca4753de0df59bf587d Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 19 Dec 2024 01:16:53 -0800 Subject: [PATCH 071/189] `best_blame_constraint`: avoid blaming assignments without user-provided types --- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 6 +-- .../rustc_borrowck/src/region_infer/mod.rs | 1 + compiler/rustc_borrowck/src/type_check/mod.rs | 16 +++++++- compiler/rustc_middle/src/mir/query.rs | 7 +++- ...egion_subtyping_basic.main.nll.0.32bit.mir | 4 +- ...egion_subtyping_basic.main.nll.0.64bit.mir | 4 +- tests/mir-opt/storage_ranges.main.nll.0.mir | 2 +- tests/ui/fn/fn_def_coercion.rs | 4 +- tests/ui/fn/fn_def_coercion.stderr | 41 +++++++++---------- .../ex3-both-anon-regions-2.rs | 2 +- .../ex3-both-anon-regions-2.stderr | 14 +++---- .../ui/match/match-ref-mut-invariance.stderr | 4 +- .../ui/match/match-ref-mut-let-invariance.rs | 2 +- .../match/match-ref-mut-let-invariance.stderr | 5 ++- .../adt-tuple-struct-calls.stderr | 18 +++++--- .../nll/user-annotations/method-ufcs-1.stderr | 7 ++-- .../nll/user-annotations/method-ufcs-2.stderr | 7 ++-- .../promoted-annotation.stderr | 6 ++- 19 files changed, 88 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2d993a3fd16f7..8a43e4b54b195 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2911,7 +2911,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( name, BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment, + category: ConstraintCategory::Assignment { .. }, from_closure: false, region_name: RegionName { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 481b8d41f10cd..78809908180ac 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -41,7 +41,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. match self { - ConstraintCategory::Assignment => "assignment ", + ConstraintCategory::Assignment { .. } => "assignment ", ConstraintCategory::Return(_) => "returning this value ", ConstraintCategory::Yield => "yielding this value ", ConstraintCategory::UseAsConst => "using this value as a constant ", @@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => { self.report_fnmut_error(&errci, kind) } - (ConstraintCategory::Assignment, true, false) + (ConstraintCategory::Assignment { .. }, true, false) | (ConstraintCategory::CallArgument(_), true, false) => { let mut db = self.report_escaping_data_error(&errci); @@ -672,7 +672,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Revert to the normal error in these cases. // Assignments aren't "escapes" in function items. if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) - || (*category == ConstraintCategory::Assignment + || (matches!(category, ConstraintCategory::Assignment { .. }) && self.regioncx.universal_regions().defining_ty.is_fn_def()) || self.regioncx.universal_regions().defining_ty.is_const() { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 4ceb2fcd8d703..7e8fad8698aef 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2034,6 +2034,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal | ConstraintCategory::Predicate(_) + | ConstraintCategory::Assignment { has_interesting_ty: false } ) && constraint.span.desugaring_kind().is_none_or(|kind| { // Try to avoid blaming constraints from desugarings, since they may not clearly // clearly match what users have written. As an exception, allow blaming returns diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 10fb8a399a267..a436edd85d92e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -892,7 +892,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } - _ => ConstraintCategory::Assignment, + Some(l) => ConstraintCategory::Assignment { + has_interesting_ty: body.local_decls[l].user_ty.is_some() + || matches!( + body.local_decls[l].local_info(), + LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_ty_info: Some(_), + .. + })) + ), + }, + // Assignments to projections should be considered interesting. + _ => ConstraintCategory::Assignment { has_interesting_ty: true }, }; debug!( "assignment category: {:?} {:?}", @@ -1226,7 +1237,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } - _ => ConstraintCategory::Assignment, + // The return type of a call is interesting for diagnostics. + _ => ConstraintCategory::Assignment { has_interesting_ty: true }, }; let locations = term_location.to_locations(); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 429be9bc725be..c2bb95a91c47e 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -250,7 +250,12 @@ pub enum ConstraintCategory<'tcx> { CallArgument(#[derive_where(skip)] Option>), CopyBound, SizedBound, - Assignment, + Assignment { + /// Whether this assignment is likely to be interesting to refer to in diagnostics. + /// Currently, this is true when it's assigning to a projection, when it's assigning from + /// the return value of a call, and when it has a user-provided type annotation. + has_interesting_ty: bool, + }, /// A constraint that came from a usage of a variable (e.g. in an ADT expression /// like `Foo { field: my_val }`) Usage, diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 35e44b2314a50..7f4a2bbbb5c34 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -17,8 +17,8 @@ | '?2 live at {bb1[0]} | '?3 live at {bb1[1..=3]} | '?4 live at {bb1[4..=7], bb2[0..=2]} -| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) -| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) +| '?2: '?3 due to Assignment { has_interesting_ty: false } at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) +| '?3: '?4 due to Assignment { has_interesting_ty: false } at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) | | Borrows | bw0: issued at bb1[0] in '?2 diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 6d415f42d06f3..1d80df76b3f77 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -17,8 +17,8 @@ | '?2 live at {bb1[0]} | '?3 live at {bb1[1..=3]} | '?4 live at {bb1[4..=7], bb2[0..=2]} -| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) -| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) +| '?2: '?3 due to Assignment { has_interesting_ty: false } at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) +| '?3: '?4 due to Assignment { has_interesting_ty: false } at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) | | Borrows | bw0: issued at bb1[0] in '?2 diff --git a/tests/mir-opt/storage_ranges.main.nll.0.mir b/tests/mir-opt/storage_ranges.main.nll.0.mir index ae8cd0c894dac..291e3bbc87354 100644 --- a/tests/mir-opt/storage_ranges.main.nll.0.mir +++ b/tests/mir-opt/storage_ranges.main.nll.0.mir @@ -15,7 +15,7 @@ | '?1 live at {bb0[0..=22]} | '?2 live at {bb0[10]} | '?3 live at {bb0[11]} -| '?2: '?3 due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:7:17: 7:25 (#0) +| '?2: '?3 due to Assignment { has_interesting_ty: false } at Single(bb0[10]) ($DIR/storage_ranges.rs:7:17: 7:25 (#0) | | Borrows | bw0: issued at bb0[10] in '?2 diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs index 31c8fa41de17c..313be6f28cdcc 100644 --- a/tests/ui/fn/fn_def_coercion.rs +++ b/tests/ui/fn/fn_def_coercion.rs @@ -46,12 +46,12 @@ fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { let x = match true { - true => foo::<&'c ()>, //~ ERROR lifetime may not live long enough + true => foo::<&'c ()>, false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough }; x(a); - x(b); + x(b); //~ ERROR lifetime may not live long enough x(c); } diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr index c2776887b79d4..ec4a1bde7fd61 100644 --- a/tests/ui/fn/fn_def_coercion.stderr +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -6,9 +6,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | | | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -22,9 +22,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -53,9 +53,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'c ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -69,9 +69,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | x = foo::<&'a ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -89,9 +89,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let x = match true { LL | true => foo::<&'b ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -105,9 +105,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -117,15 +117,15 @@ help: `'a` and `'b` must be the same: replace one with the other = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:49:17 + --> $DIR/fn_def_coercion.rs:50:18 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'c` defined here | | | lifetime `'a` defined here -LL | let x = match true { -LL | true => foo::<&'c ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` | = help: consider adding the following bound: `'a: 'c` = note: requirement occurs because of a function pointer to `foo` @@ -133,20 +133,17 @@ LL | true => foo::<&'c ()>, = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:50:18 + --> $DIR/fn_def_coercion.rs:54:5 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` +LL | x(b); + | ^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of a function pointer to `foo` - = note: the function `foo` is invariant over the parameter `T` - = help: see for more information about variance help: the following changes may resolve your lifetime errors | diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs index 66e6eb91a22e3..09ee9accccd2f 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs @@ -1,6 +1,6 @@ fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - //~^ ERROR lifetime may not live long enough *v = x; + //~^ ERROR lifetime may not live long enough } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr index e7cab52084ddd..30083b5ef5462 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -1,15 +1,13 @@ error: lifetime may not live long enough - --> $DIR/ex3-both-anon-regions-2.rs:1:14 + --> $DIR/ex3-both-anon-regions-2.rs:2:5 | LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - | ^^^^^^^^^ - - let's call the lifetime of this reference `'1` - | | | - | | let's call the lifetime of this reference `'2` - | assignment requires that `'1` must outlive `'2` + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | *v = x; + | ^^^^^^ assignment requires that `'1` must outlive `'2` | - = note: requirement occurs because of a mutable reference to `&u8` - = note: mutable references are invariant over their type parameter - = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) { diff --git a/tests/ui/match/match-ref-mut-invariance.stderr b/tests/ui/match/match-ref-mut-invariance.stderr index 93844d34b414b..b9878a1953242 100644 --- a/tests/ui/match/match-ref-mut-invariance.stderr +++ b/tests/ui/match/match-ref-mut-invariance.stderr @@ -1,12 +1,12 @@ error: lifetime may not live long enough - --> $DIR/match-ref-mut-invariance.rs:10:24 + --> $DIR/match-ref-mut-invariance.rs:10:9 | LL | impl<'b> S<'b> { | -- lifetime `'b` defined here LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | match self.0 { ref mut x => x } - | ^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` diff --git a/tests/ui/match/match-ref-mut-let-invariance.rs b/tests/ui/match/match-ref-mut-let-invariance.rs index 2c1f865b6d750..a33be09ac8be2 100644 --- a/tests/ui/match/match-ref-mut-let-invariance.rs +++ b/tests/ui/match/match-ref-mut-let-invariance.rs @@ -8,8 +8,8 @@ struct S<'b>(&'b i32); impl<'b> S<'b> { fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { let ref mut x = self.0; - //~^ ERROR lifetime may not live long enough x + //~^ ERROR lifetime may not live long enough } } diff --git a/tests/ui/match/match-ref-mut-let-invariance.stderr b/tests/ui/match/match-ref-mut-let-invariance.stderr index 3c5d73bb4f724..27968239a8e54 100644 --- a/tests/ui/match/match-ref-mut-let-invariance.stderr +++ b/tests/ui/match/match-ref-mut-let-invariance.stderr @@ -1,12 +1,13 @@ error: lifetime may not live long enough - --> $DIR/match-ref-mut-let-invariance.rs:10:13 + --> $DIR/match-ref-mut-let-invariance.rs:11:9 | LL | impl<'b> S<'b> { | -- lifetime `'b` defined here LL | fn bar<'a>(&'a mut self) -> &'a mut &'a i32 { | -- lifetime `'a` defined here LL | let ref mut x = self.0; - | ^^^^^^^^^ assignment requires that `'a` must outlive `'b` +LL | x + | ^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr index 1478ad1431ba4..2084697e7e26d 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -4,9 +4,11 @@ error[E0597]: `c` does not live long enough LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'static u32>; - | -------------------------- assignment requires that `c` is borrowed for `'static` LL | f(&c); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'static` LL | } | - `c` dropped here while still borrowed @@ -18,9 +20,11 @@ LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; - | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | } | - `c` dropped here while still borrowed @@ -33,9 +37,11 @@ LL | let _closure = || { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; - | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` LL | }; | - `c` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index 087e270c70f7d..c42ea0172cf75 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -4,10 +4,11 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... -LL | let x = <&'static u32 as Bazoom<_>>::method; - | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | ^^ borrowed value does not live long enough + | --^^------- + | | | + | | borrowed value does not live long enough + | argument requires that `a` is borrowed for `'static` LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index c89bed3b1b18f..287337c7d52d3 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -4,10 +4,11 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... -LL | let x = <&'static u32 as Bazoom<_>>::method; - | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | ^^ borrowed value does not live long enough + | --^^------- + | | | + | | borrowed value does not live long enough + | argument requires that `a` is borrowed for `'static` LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/promoted-annotation.stderr b/tests/ui/nll/user-annotations/promoted-annotation.stderr index ca99e53187091..39993475796f5 100644 --- a/tests/ui/nll/user-annotations/promoted-annotation.stderr +++ b/tests/ui/nll/user-annotations/promoted-annotation.stderr @@ -6,9 +6,11 @@ LL | fn foo<'a>() { LL | let x = 0; | - binding `x` declared here LL | let f = &drop::<&'a i32>; - | ---------------- assignment requires that `x` is borrowed for `'a` LL | f(&x); - | ^^ borrowed value does not live long enough + | --^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'a` LL | LL | } | - `x` dropped here while still borrowed From 45b2ae935dbc9feb18e9cb9f87ae04d5978e1669 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 19 Dec 2024 11:12:31 -0800 Subject: [PATCH 072/189] remove the unused `ConstraintCategory::ClosureBounds` --- compiler/rustc_borrowck/src/diagnostics/region_errors.rs | 1 - compiler/rustc_middle/src/mir/query.rs | 5 ----- 2 files changed, 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 78809908180ac..3e90ecbaf5b4e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -50,7 +50,6 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ", ConstraintCategory::CallArgument(_) => "argument ", ConstraintCategory::TypeAnnotation => "type annotation ", - ConstraintCategory::ClosureBounds => "closure body ", ConstraintCategory::SizedBound => "proving this value is `Sized` ", ConstraintCategory::CopyBound => "copying this value ", ConstraintCategory::OpaqueType => "opaque type ", diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index c2bb95a91c47e..9943914628ea6 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -241,11 +241,6 @@ pub enum ConstraintCategory<'tcx> { unsize_to: Option>, }, - /// A constraint that came from checking the body of a closure. - /// - /// We try to get the category that the closure used when reporting this. - ClosureBounds, - /// Contains the function type if available. CallArgument(#[derive_where(skip)] Option>), CopyBound, From 6421d4cf801491bb4bf3f796ec45a3f65c1a0364 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 19 Dec 2024 23:19:24 -0800 Subject: [PATCH 073/189] `best_blame_constraint`: prioritize blaming interesting-seeming constraints --- Cargo.lock | 1 - .../rustc_borrowck/src/region_infer/mod.rs | 159 ++++++++++-------- compiler/rustc_middle/Cargo.toml | 1 - compiler/rustc_middle/src/mir/query.rs | 7 +- ...-trait-obj-different-regions-lt-ext.stderr | 2 +- ...to-trait-obj-different-regions-misc.stderr | 20 ++- tests/ui/fn/fn_def_coercion.rs | 4 +- tests/ui/fn/fn_def_coercion.stderr | 32 ++-- tests/ui/issues/issue-15034.stderr | 4 +- tests/ui/lifetimes/copy_modulo_regions.stderr | 6 +- .../nll/issue-54779-anon-static-lifetime.rs | 2 +- .../issue-54779-anon-static-lifetime.stderr | 14 +- ...98589-closures-relate-named-regions.stderr | 4 +- ...insensitive-scopes-issue-117146.nll.stderr | 35 ++-- ...sitive-scopes-issue-117146.polonius.stderr | 35 ++-- ...ocation-insensitive-scopes-issue-117146.rs | 4 +- .../nll/type-check-pointer-comparisons.stderr | 24 +-- ...t-static-bound-needing-more-suggestions.rs | 2 +- ...atic-bound-needing-more-suggestions.stderr | 25 ++- .../variance-contravariant-arg-object.stderr | 2 +- .../variance-covariant-arg-object.stderr | 2 +- .../variance-invariant-arg-object.stderr | 2 +- 22 files changed, 210 insertions(+), 177 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fca4469803b4f..c525901869b15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4118,7 +4118,6 @@ name = "rustc_middle" version = "0.0.0" dependencies = [ "bitflags", - "derive-where", "either", "field-offset", "gsgdt", diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 7e8fad8698aef..7b4e82fa31010 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2026,87 +2026,102 @@ impl<'tcx> RegionInferenceContext<'tcx> { | NllRegionVariableOrigin::Existential { from_forall: true } => false, }; - let interesting_to_blame = |constraint: &OutlivesConstraint<'tcx>| { - !matches!( - constraint.category, - ConstraintCategory::OpaqueType - | ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal - | ConstraintCategory::Predicate(_) - | ConstraintCategory::Assignment { has_interesting_ty: false } - ) && constraint.span.desugaring_kind().is_none_or(|kind| { - // Try to avoid blaming constraints from desugarings, since they may not clearly - // clearly match what users have written. As an exception, allow blaming returns - // generated by `?` desugaring, since the correspondence is fairly clear. - kind == DesugaringKind::QuestionMark - && matches!(constraint.category, ConstraintCategory::Return(_)) - }) + // To pick a constraint to blame, we organize constraints by how interesting we expect them + // to be in diagnostics, then pick the most interesting one closest to either the source or + // the target on our constraint path. + let constraint_interest = |constraint: &OutlivesConstraint<'tcx>| { + // Try to avoid blaming constraints from desugarings, since they may not clearly match + // match what users have written. As an exception, allow blaming returns generated by + // `?` desugaring, since the correspondence is fairly clear. + let category = if let Some(kind) = constraint.span.desugaring_kind() + && (kind != DesugaringKind::QuestionMark + || !matches!(constraint.category, ConstraintCategory::Return(_))) + { + ConstraintCategory::Boring + } else { + constraint.category + }; + + match category { + // Returns usually provide a type to blame and have specially written diagnostics, + // so prioritize them. + ConstraintCategory::Return(_) => 0, + // Unsizing coercions are interesting, since we have a note for that: + // `BorrowExplanation::add_object_lifetime_default_note`. + // FIXME(dianne): That note shouldn't depend on a coercion being blamed; see issue + // #131008 for an example of where we currently don't emit it but should. + // Once the note is handled properly, this case should be removed. Until then, it + // should be as limited as possible; the note is prone to false positives and this + // constraint usually isn't best to blame. + ConstraintCategory::Cast { + unsize_to: Some(unsize_ty), + is_implicit_coercion: true, + } if target_region == self.universal_regions().fr_static + // Mirror the note's condition, to minimize how often this diverts blame. + && let ty::Adt(_, args) = unsize_ty.kind() + && args.iter().any(|arg| arg.as_type().is_some_and(|ty| ty.is_trait())) + // Mimic old logic for this, to minimize false positives in tests. + && !path + .iter() + .any(|c| matches!(c.category, ConstraintCategory::TypeAnnotation)) => + { + 1 + } + // Between other interesting constraints, order by their position on the `path`. + ConstraintCategory::Yield + | ConstraintCategory::UseAsConst + | ConstraintCategory::UseAsStatic + | ConstraintCategory::TypeAnnotation + | ConstraintCategory::Cast { .. } + | ConstraintCategory::CallArgument(_) + | ConstraintCategory::CopyBound + | ConstraintCategory::SizedBound + | ConstraintCategory::Assignment { has_interesting_ty: true } + | ConstraintCategory::Usage + | ConstraintCategory::ClosureUpvar(_) => 2, + // Give assignments a lower priority when flagged as less likely to be interesting. + // In particular, de-prioritize MIR assignments lowered from argument patterns. + ConstraintCategory::Assignment { has_interesting_ty: false } => 3, + // We handle predicates and opaque types specially; don't prioritize them here. + ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4, + // `Boring` constraints can correspond to user-written code and have useful spans, + // but don't provide any other useful information for diagnostics. + ConstraintCategory::Boring => 5, + // `BoringNoLocation` constraints can point to user-written code, but are less + // specific, and are not used for relations that would make sense to blame. + ConstraintCategory::BoringNoLocation => 6, + // Do not blame internal constraints. + ConstraintCategory::Internal => 7, + ConstraintCategory::IllegalUniverse => 8, + } }; let best_choice = if blame_source { - path.iter().rposition(interesting_to_blame) + path.iter().enumerate().rev().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0 } else { - path.iter().position(interesting_to_blame) + path.iter().enumerate().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0 }; debug!(?best_choice, ?blame_source); - let best_constraint = match best_choice { - Some(i) - if let Some(next) = path.get(i + 1) - && matches!(path[i].category, ConstraintCategory::Return(_)) - && next.category == ConstraintCategory::OpaqueType => - { - // The return expression is being influenced by the return type being - // impl Trait, point at the return type and not the return expr. - *next - } - - Some(i) - if path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) - && let Some(field) = path.iter().find_map(|p| { - if let ConstraintCategory::ClosureUpvar(f) = p.category { - Some(f) - } else { - None - } - }) => - { - OutlivesConstraint { - category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)), - ..path[i] - } - } - - Some(_) - if target_region == self.universal_regions().fr_static - && let Some(old_best) = path.iter().min_by_key(|p| p.category) - && matches!(old_best.category, ConstraintCategory::Cast { - is_implicit_coercion: true, - unsize_to: Some(_) - }) => - { - // FIXME(dianne): This is a hack in order to emit the subdiagnostic - // `BorrowExplanation::add_object_lifetime_default_note` more often, e.g. on - // `tests/ui/traits/trait-object-lifetime-default-note.rs`. The subdiagnostic - // depends on a coercion being blamed, so we fall back to an earlier version of this - // function's blaming logic to keep the test result the same. A proper fix will - // require rewriting the subdiagnostic not to rely on a coercion being blamed. - // For examples of where notes are missing, see #131008 and - // `tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs`. - // As part of fixing those, this case should be removed. - *old_best - } - - Some(i) => path[i], - - None => { - // If that search fails, the only constraints on the path are those that we try not - // to blame. In that case, find what appears to be the most interesting point to - // report to the user via an even more ad-hoc guess. - *path.iter().min_by_key(|p| p.category).unwrap() + let best_constraint = if let Some(next) = path.get(best_choice + 1) + && matches!(path[best_choice].category, ConstraintCategory::Return(_)) + && next.category == ConstraintCategory::OpaqueType + { + // The return expression is being influenced by the return type being + // impl Trait, point at the return type and not the return expr. + *next + } else if path[best_choice].category == ConstraintCategory::Return(ReturnConstraint::Normal) + && let Some(field) = path.iter().find_map(|p| { + if let ConstraintCategory::ClosureUpvar(f) = p.category { Some(f) } else { None } + }) + { + OutlivesConstraint { + category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)), + ..path[best_choice] } + } else { + path[best_choice] }; let blame_constraint = BlameConstraint { diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index e64500f812a1d..2c34df6ea61a3 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -derive-where = "1.2.7" either = "1.5.0" field-offset = "0.3.5" gsgdt = "0.1.2" diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 9943914628ea6..8ab994a2dad6c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -3,7 +3,6 @@ use std::cell::Cell; use std::fmt::{self, Debug}; -use derive_where::derive_where; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; @@ -225,7 +224,6 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] -#[derive_where(PartialOrd, Ord)] pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, @@ -237,12 +235,11 @@ pub enum ConstraintCategory<'tcx> { is_implicit_coercion: bool, /// Whether this is an unsizing coercion and if yes, this contains the target type. /// Region variables are erased to ReErased. - #[derive_where(skip)] unsize_to: Option>, }, /// Contains the function type if available. - CallArgument(#[derive_where(skip)] Option>), + CallArgument(Option>), CopyBound, SizedBound, Assignment { @@ -276,7 +273,7 @@ pub enum ConstraintCategory<'tcx> { IllegalUniverse, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] pub enum ReturnConstraint { Normal, diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr index ed9ebce4832c2..b7319e3356bd0 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> { | -- lifetime `'a` defined here LL | x as _ - | ^^^^^^ cast requires that `'a` must outlive `'static` + | ^^^^^^ returning this value requires that `'a` must outlive `'static` error: aborting due to 1 previous error diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr index 6eeaeb120a729..faaa6325f3495 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr @@ -6,9 +6,12 @@ LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> { | | | lifetime `'a` defined here LL | x as _ - | ^^^^^^ cast requires that `'b` must outlive `'a` + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>` + = note: mutable pointers are invariant over their type parameter + = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5 @@ -35,9 +38,12 @@ LL | fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> { | | | lifetime `'a` defined here LL | x as _ - | ^^^^^^ cast requires that `'b` must outlive `'a` + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>` + = note: mutable pointers are invariant over their type parameter + = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:15:5 @@ -85,9 +91,12 @@ LL | fn change_assoc_0<'a, 'b>( | lifetime `'a` defined here ... LL | x as _ - | ^^^^^^ cast requires that `'b` must outlive `'a` + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable pointer to `dyn Assocked` + = note: mutable pointers are invariant over their type parameter + = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5 @@ -118,9 +127,12 @@ LL | fn change_assoc_1<'a, 'b>( | lifetime `'a` defined here ... LL | x as _ - | ^^^^^^ cast requires that `'b` must outlive `'a` + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable pointer to `dyn Assocked>` + = note: mutable pointers are invariant over their type parameter + = help: see for more information about variance error: lifetime may not live long enough --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5 diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs index 313be6f28cdcc..eea9e480827fb 100644 --- a/tests/ui/fn/fn_def_coercion.rs +++ b/tests/ui/fn/fn_def_coercion.rs @@ -46,8 +46,8 @@ fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { let x = match true { - true => foo::<&'c ()>, - false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + true => foo::<&'c ()>, //~ ERROR lifetime may not live long enough + false => foo::<&'a ()>, }; x(a); diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr index ec4a1bde7fd61..a4dc72310815b 100644 --- a/tests/ui/fn/fn_def_coercion.stderr +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -6,9 +6,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | | | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -22,9 +22,9 @@ LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'a ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -53,9 +53,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let mut x = foo::<&'c ()>; LL | x = foo::<&'b ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -69,9 +69,9 @@ LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | x = foo::<&'a ()>; - | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -89,9 +89,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here LL | let x = match true { LL | true => foo::<&'b ()>, - | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -105,9 +105,9 @@ LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | lifetime `'a` defined here ... LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `foo` = note: the function `foo` is invariant over the parameter `T` = help: see for more information about variance @@ -117,15 +117,15 @@ help: `'a` and `'b` must be the same: replace one with the other = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:50:18 + --> $DIR/fn_def_coercion.rs:49:17 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'c` defined here | | | lifetime `'a` defined here -... -LL | false => foo::<&'a ()>, - | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` +LL | let x = match true { +LL | true => foo::<&'c ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` | = help: consider adding the following bound: `'a: 'c` = note: requirement occurs because of a function pointer to `foo` diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/issues/issue-15034.stderr index c5bc31f94d981..587a5c85e924a 100644 --- a/tests/ui/issues/issue-15034.stderr +++ b/tests/ui/issues/issue-15034.stderr @@ -1,10 +1,10 @@ error[E0621]: explicit lifetime required in the type of `lexer` - --> $DIR/issue-15034.rs:17:25 + --> $DIR/issue-15034.rs:17:9 | LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> { | ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>` LL | Parser { lexer: lexer } - | ^^^^^ lifetime `'a` required + | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/copy_modulo_regions.stderr b/tests/ui/lifetimes/copy_modulo_regions.stderr index 920fec09103b2..310ddb21647f6 100644 --- a/tests/ui/lifetimes/copy_modulo_regions.stderr +++ b/tests/ui/lifetimes/copy_modulo_regions.stderr @@ -4,7 +4,11 @@ error: lifetime may not live long enough LL | fn foo<'a>() -> [Foo<'a>; 100] { | -- lifetime `'a` defined here LL | [mk_foo::<'a>(); 100] - | ^^^^^^^^^^^^^^^^^^^^^ copying this value requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Foo<'a>` is invariant over the parameter `'a` + = help: see for more information about variance error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.rs b/tests/ui/nll/issue-54779-anon-static-lifetime.rs index 1dab7c1712afe..6b8fa608ebbb2 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.rs +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.rs @@ -29,7 +29,7 @@ impl DebugWith for Foo { fmt: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { let Foo { bar } = self; - bar.debug_with(cx); //~ lifetime may not live long enough + bar.debug_with(cx); //~ borrowed data escapes outside of method Ok(()) } } diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr index a454ed265685c..03a5590661422 100644 --- a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr +++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr @@ -1,11 +1,17 @@ -error: lifetime may not live long enough - --> $DIR/issue-54779-anon-static-lifetime.rs:32:24 +error[E0521]: borrowed data escapes outside of method + --> $DIR/issue-54779-anon-static-lifetime.rs:32:9 | LL | cx: &dyn DebugContext, - | - let's call the lifetime of this reference `'1` + | -- - let's call the lifetime of this reference `'1` + | | + | `cx` is a reference that is only valid in the method body ... LL | bar.debug_with(cx); - | ^^ coercion requires that `'1` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^ + | | + | `cx` escapes the method body here + | argument requires that `'1` must outlive `'static` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr index 4e741abc2dcf2..4f244b54bd07b 100644 --- a/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr +++ b/tests/ui/nll/issue-98589-closures-relate-named-regions.stderr @@ -11,14 +11,14 @@ LL | || { None::<&'a &'b ()>; }; = help: consider adding the following bound: `'b: 'a` error: lifetime may not live long enough - --> $DIR/issue-98589-closures-relate-named-regions.rs:15:10 + --> $DIR/issue-98589-closures-relate-named-regions.rs:15:5 | LL | fn test_early_late<'a: 'a, 'b>() { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | || { None::<&'a &'b ()>; }; - | ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index e4b323bc2b6ac..1d086c658dfcd 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -1,20 +1,23 @@ -error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function - --> $DIR/location-insensitive-scopes-issue-117146.rs:10:13 +error[E0597]: `a` does not live long enough + --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 | +LL | let a = (); + | - binding `a` declared here LL | let b = |_| &a; - | ^^^ - `a` is borrowed here - | | - | may outlive borrowed value `a` - | -note: function requires argument type to outlive `'static` - --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 - | -LL | bad(&b); - | ^^^^^^^ -help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword - | -LL | let b = move |_| &a; - | ++++ + | --- -^ + | | || + | | |borrowed value does not live long enough + | | returning this value requires that `a` is borrowed for `'static` + | value captured here +... +LL | } + | - `a` dropped here while still borrowed + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + | +LL | fn bad &()>(_: F) {} + | ^^^ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -36,4 +39,4 @@ LL | bad(&b); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0373`. +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index e4b323bc2b6ac..1d086c658dfcd 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -1,20 +1,23 @@ -error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function - --> $DIR/location-insensitive-scopes-issue-117146.rs:10:13 +error[E0597]: `a` does not live long enough + --> $DIR/location-insensitive-scopes-issue-117146.rs:10:18 | +LL | let a = (); + | - binding `a` declared here LL | let b = |_| &a; - | ^^^ - `a` is borrowed here - | | - | may outlive borrowed value `a` - | -note: function requires argument type to outlive `'static` - --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 - | -LL | bad(&b); - | ^^^^^^^ -help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword - | -LL | let b = move |_| &a; - | ++++ + | --- -^ + | | || + | | |borrowed value does not live long enough + | | returning this value requires that `a` is borrowed for `'static` + | value captured here +... +LL | } + | - `a` dropped here while still borrowed + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + | +LL | fn bad &()>(_: F) {} + | ^^^ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -36,4 +39,4 @@ LL | bad(&b); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0373`. +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs index bd26af5bee25c..c828a37521e0e 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs @@ -8,8 +8,8 @@ fn main() { let a = (); let b = |_| &a; - //[nll]~^ ERROR closure may outlive the current function, but it borrows `a` - //[polonius]~^^ ERROR closure may outlive the current function, but it borrows `a` + //[nll]~^ ERROR `a` does not live long enough + //[polonius]~^^ ERROR `a` does not live long enough bad(&b); //[nll]~^ ERROR implementation of `Fn` //[nll]~| ERROR implementation of `FnOnce` diff --git a/tests/ui/nll/type-check-pointer-comparisons.stderr b/tests/ui/nll/type-check-pointer-comparisons.stderr index 37098b585dfea..90cdb92e81b26 100644 --- a/tests/ui/nll/type-check-pointer-comparisons.stderr +++ b/tests/ui/nll/type-check-pointer-comparisons.stderr @@ -6,9 +6,9 @@ LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'a` must outlive `'b` + | ^ requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance @@ -21,9 +21,9 @@ LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'b` must outlive `'a` + | ^ requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance @@ -38,9 +38,9 @@ LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'a` must outlive `'b` + | ^ requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable pointer to `&i32` = note: mutable pointers are invariant over their type parameter = help: see for more information about variance @@ -53,9 +53,9 @@ LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'b` must outlive `'a` + | ^ requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable pointer to `&i32` = note: mutable pointers are invariant over their type parameter = help: see for more information about variance @@ -72,9 +72,9 @@ LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32 | | | lifetime `'a` defined here LL | f == g; - | ^ requires that `'a` must outlive `'b` + | ^ requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance @@ -87,9 +87,9 @@ LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32 | | | lifetime `'a` defined here LL | f == g; - | ^ requires that `'b` must outlive `'a` + | ^ requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs index 8f3171222bb6f..c24672816acdb 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs @@ -64,7 +64,7 @@ mod bay { fn use_it<'a>(val: Box + 'a>) -> &'a () { val.use_self() - //~^ ERROR: `val` does not live long enough + //~^ ERROR: cannot return value referencing function parameter `val` //~| ERROR: borrowed data escapes outside of function } } diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index a8a854220b4e5..505765d2b41f6 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -25,20 +25,6 @@ LL | val.use_self() | returns a value referencing data owned by the current function | `val` is borrowed here -error[E0597]: `val` does not live long enough - --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9 - | -LL | fn use_it<'a>(val: Box + 'a>) -> &'a () { - | --- binding `val` declared here -LL | val.use_self() - | ^^^----------- - | | - | borrowed value does not live long enough - | argument requires that `val` is borrowed for `'static` -... -LL | } - | - `val` dropped here while still borrowed - error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9 | @@ -64,6 +50,15 @@ help: consider relaxing the implicit `'static` requirement LL | impl MyTrait for Box + '_> { | ++++ +error[E0515]: cannot return value referencing function parameter `val` + --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:9 + | +LL | val.use_self() + | ---^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `val` is borrowed here + error[E0515]: cannot return value referencing function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:90:9 | @@ -75,5 +70,5 @@ LL | val.use_self() error: aborting due to 6 previous errors -Some errors have detailed explanations: E0515, E0521, E0597. +Some errors have detailed explanations: E0515, E0521. For more information about an error, try `rustc --explain E0515`. diff --git a/tests/ui/variance/variance-contravariant-arg-object.stderr b/tests/ui/variance/variance-contravariant-arg-object.stderr index 7d7c6cb28cdf0..ab28315e11e52 100644 --- a/tests/ui/variance/variance-contravariant-arg-object.stderr +++ b/tests/ui/variance/variance-contravariant-arg-object.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box>) | lifetime `'min` defined here ... LL | v - | ^ coercion requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/tests/ui/variance/variance-covariant-arg-object.stderr b/tests/ui/variance/variance-covariant-arg-object.stderr index 4e82c8e8e1b4b..51f8cb3ec750b 100644 --- a/tests/ui/variance/variance-covariant-arg-object.stderr +++ b/tests/ui/variance/variance-covariant-arg-object.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box>) | lifetime `'min` defined here ... LL | v - | ^ coercion requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` diff --git a/tests/ui/variance/variance-invariant-arg-object.stderr b/tests/ui/variance/variance-invariant-arg-object.stderr index e3969ebebcea4..9793a36be06ab 100644 --- a/tests/ui/variance/variance-invariant-arg-object.stderr +++ b/tests/ui/variance/variance-invariant-arg-object.stderr @@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box>) | lifetime `'min` defined here ... LL | v - | ^ coercion requires that `'min` must outlive `'max` + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` | = help: consider adding the following bound: `'min: 'max` From 10061b3a4fea7e6268a2d4618504c4bee3ca61fb Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 20 Dec 2024 17:08:27 -0800 Subject: [PATCH 074/189] make outlives constraints from generic arguments less boring --- .../src/diagnostics/region_errors.rs | 5 ++-- .../rustc_borrowck/src/region_infer/mod.rs | 26 ++++++++++++------- compiler/rustc_borrowck/src/type_check/mod.rs | 10 +++---- compiler/rustc_middle/src/mir/query.rs | 11 +++++++- ...ied-bounds-unnorm-associated-type-2.stderr | 2 +- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 3e90ecbaf5b4e..51fe47f878179 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -13,7 +13,7 @@ use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; -use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; +use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor}; use rustc_span::{Ident, Span, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -49,7 +49,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { ConstraintCategory::Cast { is_implicit_coercion: false, .. } => "cast ", ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ", ConstraintCategory::CallArgument(_) => "argument ", - ConstraintCategory::TypeAnnotation => "type annotation ", + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => "generic argument ", + ConstraintCategory::TypeAnnotation(_) => "type annotation ", ConstraintCategory::SizedBound => "proving this value is `Sized` ", ConstraintCategory::CopyBound => "copying this value ", ConstraintCategory::OpaqueType => "opaque type ", diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 7b4e82fa31010..73e25cbae27ed 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -13,9 +13,9 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ - BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy, - ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, - TerminatorKind, + AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, + ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location, + ReturnConstraint, TerminatorKind, }; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::fold::fold_regions; @@ -2063,7 +2063,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Mimic old logic for this, to minimize false positives in tests. && !path .iter() - .any(|c| matches!(c.category, ConstraintCategory::TypeAnnotation)) => + .any(|c| matches!(c.category, ConstraintCategory::TypeAnnotation(_))) => { 1 } @@ -2071,7 +2071,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::Yield | ConstraintCategory::UseAsConst | ConstraintCategory::UseAsStatic - | ConstraintCategory::TypeAnnotation + | ConstraintCategory::TypeAnnotation( + AnnotationSource::Ascription + | AnnotationSource::Declaration + | AnnotationSource::OpaqueCast, + ) | ConstraintCategory::Cast { .. } | ConstraintCategory::CallArgument(_) | ConstraintCategory::CopyBound @@ -2082,17 +2086,19 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Give assignments a lower priority when flagged as less likely to be interesting. // In particular, de-prioritize MIR assignments lowered from argument patterns. ConstraintCategory::Assignment { has_interesting_ty: false } => 3, + // Generic arguments are unlikely to be what relates regions together + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 4, // We handle predicates and opaque types specially; don't prioritize them here. - ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4, + ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 5, // `Boring` constraints can correspond to user-written code and have useful spans, // but don't provide any other useful information for diagnostics. - ConstraintCategory::Boring => 5, + ConstraintCategory::Boring => 6, // `BoringNoLocation` constraints can point to user-written code, but are less // specific, and are not used for relations that would make sense to blame. - ConstraintCategory::BoringNoLocation => 6, + ConstraintCategory::BoringNoLocation => 7, // Do not blame internal constraints. - ConstraintCategory::Internal => 7, - ConstraintCategory::IllegalUniverse => 8, + ConstraintCategory::Internal => 8, + ConstraintCategory::IllegalUniverse => 9, } }; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a436edd85d92e..d11e86aea35a7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -298,7 +298,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { context.ambient_variance(), base_ty.ty, location.to_locations(), - ConstraintCategory::TypeAnnotation, + ConstraintCategory::TypeAnnotation(AnnotationSource::OpaqueCast), ) .unwrap(); } @@ -333,7 +333,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, - ConstraintCategory::Boring, + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), ) { let annotation = &self.typeck.user_type_annotations[annotation_index]; span_mirbug!( @@ -455,7 +455,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ty::Invariant, user_ty, Locations::All(*span), - ConstraintCategory::TypeAnnotation, + ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), ) { span_mirbug!( self, @@ -938,7 +938,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, location.to_locations(), - ConstraintCategory::Boring, + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), ) { let annotation = &self.user_type_annotations[annotation_index]; span_mirbug!( @@ -973,7 +973,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { *variance, projection, Locations::All(stmt.source_info.span), - ConstraintCategory::TypeAnnotation, + ConstraintCategory::TypeAnnotation(AnnotationSource::Ascription), ) { let annotation = &self.user_type_annotations[projection.base]; span_mirbug!( diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 8ab994a2dad6c..f2fbc63ee4112 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -229,7 +229,7 @@ pub enum ConstraintCategory<'tcx> { Yield, UseAsConst, UseAsStatic, - TypeAnnotation, + TypeAnnotation(AnnotationSource), Cast { /// Whether this cast is a coercion that was automatically inserted by the compiler. is_implicit_coercion: bool, @@ -280,6 +280,15 @@ pub enum ReturnConstraint { ClosureUpvar(FieldIdx), } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] +pub enum AnnotationSource { + Ascription, + Declaration, + OpaqueCast, + GenericArg, +} + /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing /// that must outlive some region. #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr index e57b5af82cded..85e3452fbf2ca 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-2.stderr @@ -6,7 +6,7 @@ LL | fn g<'a, 'b>() { | | | lifetime `'a` defined here LL | f::<'a, 'b>(()); - | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + | ^^^^^^^^^^^^^^^ generic argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a function pointer to `f` From 2c5815b2855e74beb608e2a4985bec135c4586dd Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 20 Dec 2024 18:33:12 -0800 Subject: [PATCH 075/189] make outlives constraints from pointer comparisons less boring --- compiler/rustc_borrowck/src/type_check/mod.rs | 4 +-- .../nll/type-check-pointer-comparisons.stderr | 30 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d11e86aea35a7..495ec956f35a8 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2181,7 +2181,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ty_left, common_ty, location.to_locations(), - ConstraintCategory::Boring, + ConstraintCategory::CallArgument(None), ) .unwrap_or_else(|err| { bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) @@ -2190,7 +2190,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ty_right, common_ty, location.to_locations(), - ConstraintCategory::Boring, + ConstraintCategory::CallArgument(None), ) { span_mirbug!( self, diff --git a/tests/ui/nll/type-check-pointer-comparisons.stderr b/tests/ui/nll/type-check-pointer-comparisons.stderr index 90cdb92e81b26..e362dfb3c6e7a 100644 --- a/tests/ui/nll/type-check-pointer-comparisons.stderr +++ b/tests/ui/nll/type-check-pointer-comparisons.stderr @@ -6,24 +6,24 @@ LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'b` must outlive `'a` + | ^^^^^^ argument requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/type-check-pointer-comparisons.rs:4:10 + --> $DIR/type-check-pointer-comparisons.rs:4:5 | LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'a` must outlive `'b` + | ^^^^^^ argument requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance @@ -38,24 +38,24 @@ LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'b` must outlive `'a` + | ^^^^^^ argument requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable pointer to `&i32` = note: mutable pointers are invariant over their type parameter = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/type-check-pointer-comparisons.rs:10:10 + --> $DIR/type-check-pointer-comparisons.rs:10:5 | LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | x == y; - | ^ requires that `'a` must outlive `'b` + | ^^^^^^ argument requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable pointer to `&i32` = note: mutable pointers are invariant over their type parameter = help: see for more information about variance @@ -72,24 +72,24 @@ LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32 | | | lifetime `'a` defined here LL | f == g; - | ^ requires that `'b` must outlive `'a` + | ^^^^^^ argument requires that `'a` must outlive `'b` | - = help: consider adding the following bound: `'b: 'a` + = help: consider adding the following bound: `'a: 'b` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/type-check-pointer-comparisons.rs:16:10 + --> $DIR/type-check-pointer-comparisons.rs:16:5 | LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | f == g; - | ^ requires that `'a` must outlive `'b` + | ^^^^^^ argument requires that `'b` must outlive `'a` | - = help: consider adding the following bound: `'a: 'b` + = help: consider adding the following bound: `'b: 'a` = note: requirement occurs because of a mutable reference to `&i32` = note: mutable references are invariant over their type parameter = help: see for more information about variance From 1b2281a49321e8a3b839dd69fce4b738e50e770a Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 20 Dec 2024 21:14:16 -0800 Subject: [PATCH 076/189] point out unblamed constraints from `Copy`/`Sized` bounds in region errors --- .../src/diagnostics/explain_borrow.rs | 1 + .../rustc_borrowck/src/diagnostics/mod.rs | 22 +++++++++++++++++++ .../src/diagnostics/region_errors.rs | 1 + .../multiple-lifetimes/error-handling.stderr | 3 +++ tests/ui/lifetimes/copy_modulo_regions.stderr | 5 ++++- 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 860d6338a0284..48f28f3f1de95 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -331,6 +331,7 @@ impl<'tcx> BorrowExplanation<'tcx> { }; cx.add_placeholder_from_predicate_note(err, &path); + cx.add_sized_or_copy_bound_info(err, category, &path); if let ConstraintCategory::Cast { is_implicit_coercion: true, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index c9100f23e12e7..0286ea6cd9dca 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -37,6 +37,7 @@ use super::MirBorrowckCtxt; use super::borrow_set::BorrowData; use crate::constraints::OutlivesConstraint; use crate::fluent_generated as fluent; +use crate::nll::ConstraintDescription; use crate::session_diagnostics::{ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, @@ -647,6 +648,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); } } + + /// Add a label to region errors and borrow explanations when outlives constraints arise from + /// proving a type implements `Sized` or `Copy`. + fn add_sized_or_copy_bound_info( + &self, + err: &mut Diag<'_>, + blamed_category: ConstraintCategory<'tcx>, + path: &[OutlivesConstraint<'tcx>], + ) { + for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] { + if sought_category != blamed_category + && let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category) + { + let label = format!( + "requirement occurs due to {}", + sought_category.description().trim_end() + ); + err.span_label(sought_constraint.span, label); + } + } + } } /// The span(s) associated to a use of a place. diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 51fe47f878179..051778dcace80 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -554,6 +554,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } self.add_placeholder_from_predicate_note(&mut diag, &path); + self.add_sized_or_copy_bound_info(&mut diag, category, &path); self.buffer_error(diag); } diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr index 00709ee7438a7..945fb0fc618fb 100644 --- a/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr @@ -6,6 +6,9 @@ LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { | | | lifetime `'a` defined here ... +LL | let u = v; + | - requirement occurs due to copying this value +... LL | let _: &'b i32 = *u.0; | ^^^^^^^ type annotation requires that `'a` must outlive `'b` | diff --git a/tests/ui/lifetimes/copy_modulo_regions.stderr b/tests/ui/lifetimes/copy_modulo_regions.stderr index 310ddb21647f6..0d69f0323d621 100644 --- a/tests/ui/lifetimes/copy_modulo_regions.stderr +++ b/tests/ui/lifetimes/copy_modulo_regions.stderr @@ -4,7 +4,10 @@ error: lifetime may not live long enough LL | fn foo<'a>() -> [Foo<'a>; 100] { | -- lifetime `'a` defined here LL | [mk_foo::<'a>(); 100] - | ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^ + | | + | returning this value requires that `'a` must outlive `'static` + | requirement occurs due to copying this value | = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant = note: the struct `Foo<'a>` is invariant over the parameter `'a` From fe8b12f8cfd27984a6102c441b49023d5bce0b02 Mon Sep 17 00:00:00 2001 From: dianne Date: Sat, 21 Dec 2024 13:23:57 -0800 Subject: [PATCH 077/189] only avoid blaming assignments from argument patterns --- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 6 ++-- .../rustc_borrowck/src/region_infer/mod.rs | 17 +++++------ compiler/rustc_borrowck/src/type_check/mod.rs | 28 ++++++++++--------- compiler/rustc_middle/src/mir/query.rs | 7 +---- ...egion_subtyping_basic.main.nll.0.32bit.mir | 4 +-- ...egion_subtyping_basic.main.nll.0.64bit.mir | 4 +-- tests/mir-opt/storage_ranges.main.nll.0.mir | 2 +- tests/ui/fn/fn_def_coercion.rs | 4 +-- tests/ui/fn/fn_def_coercion.stderr | 9 ++++-- .../adt-tuple-struct-calls.stderr | 18 ++++-------- .../nll/user-annotations/method-ufcs-1.stderr | 7 ++--- .../nll/user-annotations/method-ufcs-2.stderr | 7 ++--- .../promoted-annotation.stderr | 6 ++-- 14 files changed, 54 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8a43e4b54b195..2d993a3fd16f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2911,7 +2911,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( name, BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment { .. }, + category: ConstraintCategory::Assignment, from_closure: false, region_name: RegionName { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 051778dcace80..f0baa20648cd2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -41,7 +41,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. match self { - ConstraintCategory::Assignment { .. } => "assignment ", + ConstraintCategory::Assignment => "assignment ", ConstraintCategory::Return(_) => "returning this value ", ConstraintCategory::Yield => "yielding this value ", ConstraintCategory::UseAsConst => "using this value as a constant ", @@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => { self.report_fnmut_error(&errci, kind) } - (ConstraintCategory::Assignment { .. }, true, false) + (ConstraintCategory::Assignment, true, false) | (ConstraintCategory::CallArgument(_), true, false) => { let mut db = self.report_escaping_data_error(&errci); @@ -673,7 +673,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Revert to the normal error in these cases. // Assignments aren't "escapes" in function items. if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) - || (matches!(category, ConstraintCategory::Assignment { .. }) + || (*category == ConstraintCategory::Assignment && self.regioncx.universal_regions().defining_ty.is_fn_def()) || self.regioncx.universal_regions().defining_ty.is_const() { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 73e25cbae27ed..d6375c5dc2701 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2080,25 +2080,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { | ConstraintCategory::CallArgument(_) | ConstraintCategory::CopyBound | ConstraintCategory::SizedBound - | ConstraintCategory::Assignment { has_interesting_ty: true } + | ConstraintCategory::Assignment | ConstraintCategory::Usage | ConstraintCategory::ClosureUpvar(_) => 2, - // Give assignments a lower priority when flagged as less likely to be interesting. - // In particular, de-prioritize MIR assignments lowered from argument patterns. - ConstraintCategory::Assignment { has_interesting_ty: false } => 3, // Generic arguments are unlikely to be what relates regions together - ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 4, + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 3, // We handle predicates and opaque types specially; don't prioritize them here. - ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 5, + ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4, // `Boring` constraints can correspond to user-written code and have useful spans, // but don't provide any other useful information for diagnostics. - ConstraintCategory::Boring => 6, + ConstraintCategory::Boring => 5, // `BoringNoLocation` constraints can point to user-written code, but are less // specific, and are not used for relations that would make sense to blame. - ConstraintCategory::BoringNoLocation => 7, + ConstraintCategory::BoringNoLocation => 6, // Do not blame internal constraints. - ConstraintCategory::Internal => 8, - ConstraintCategory::IllegalUniverse => 9, + ConstraintCategory::Internal => 7, + ConstraintCategory::IllegalUniverse => 8, } }; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 495ec956f35a8..1eb471968b285 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -892,18 +892,20 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } - Some(l) => ConstraintCategory::Assignment { - has_interesting_ty: body.local_decls[l].user_ty.is_some() - || matches!( - body.local_decls[l].local_info(), - LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_ty_info: Some(_), - .. - })) - ), - }, - // Assignments to projections should be considered interesting. - _ => ConstraintCategory::Assignment { has_interesting_ty: true }, + Some(_) + if let Some(body_id) = tcx + .hir_node_by_def_id(body.source.def_id().expect_local()) + .body_id() + && let params = tcx.hir().body(body_id).params + && params + .iter() + .any(|param| param.span.contains(stmt.source_info.span)) => + { + // Assignments generated from lowering argument patterns shouldn't be called + // "assignments" in diagnostics and aren't interesting to blame for errors. + ConstraintCategory::Boring + } + _ => ConstraintCategory::Assignment, }; debug!( "assignment category: {:?} {:?}", @@ -1238,7 +1240,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring } // The return type of a call is interesting for diagnostics. - _ => ConstraintCategory::Assignment { has_interesting_ty: true }, + _ => ConstraintCategory::Assignment, }; let locations = term_location.to_locations(); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index f2fbc63ee4112..db5da941f1e7b 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -242,12 +242,7 @@ pub enum ConstraintCategory<'tcx> { CallArgument(Option>), CopyBound, SizedBound, - Assignment { - /// Whether this assignment is likely to be interesting to refer to in diagnostics. - /// Currently, this is true when it's assigning to a projection, when it's assigning from - /// the return value of a call, and when it has a user-provided type annotation. - has_interesting_ty: bool, - }, + Assignment, /// A constraint that came from a usage of a variable (e.g. in an ADT expression /// like `Foo { field: my_val }`) Usage, diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 7f4a2bbbb5c34..35e44b2314a50 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -17,8 +17,8 @@ | '?2 live at {bb1[0]} | '?3 live at {bb1[1..=3]} | '?4 live at {bb1[4..=7], bb2[0..=2]} -| '?2: '?3 due to Assignment { has_interesting_ty: false } at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) -| '?3: '?4 due to Assignment { has_interesting_ty: false } at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) +| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) +| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) | | Borrows | bw0: issued at bb1[0] in '?2 diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 1d80df76b3f77..6d415f42d06f3 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -17,8 +17,8 @@ | '?2 live at {bb1[0]} | '?3 live at {bb1[1..=3]} | '?4 live at {bb1[4..=7], bb2[0..=2]} -| '?2: '?3 due to Assignment { has_interesting_ty: false } at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) -| '?3: '?4 due to Assignment { has_interesting_ty: false } at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) +| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) +| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) | | Borrows | bw0: issued at bb1[0] in '?2 diff --git a/tests/mir-opt/storage_ranges.main.nll.0.mir b/tests/mir-opt/storage_ranges.main.nll.0.mir index 291e3bbc87354..ae8cd0c894dac 100644 --- a/tests/mir-opt/storage_ranges.main.nll.0.mir +++ b/tests/mir-opt/storage_ranges.main.nll.0.mir @@ -15,7 +15,7 @@ | '?1 live at {bb0[0..=22]} | '?2 live at {bb0[10]} | '?3 live at {bb0[11]} -| '?2: '?3 due to Assignment { has_interesting_ty: false } at Single(bb0[10]) ($DIR/storage_ranges.rs:7:17: 7:25 (#0) +| '?2: '?3 due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:7:17: 7:25 (#0) | | Borrows | bw0: issued at bb0[10] in '?2 diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs index eea9e480827fb..31c8fa41de17c 100644 --- a/tests/ui/fn/fn_def_coercion.rs +++ b/tests/ui/fn/fn_def_coercion.rs @@ -47,11 +47,11 @@ fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { let x = match true { true => foo::<&'c ()>, //~ ERROR lifetime may not live long enough - false => foo::<&'a ()>, + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough }; x(a); - x(b); //~ ERROR lifetime may not live long enough + x(b); x(c); } diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr index a4dc72310815b..c2776887b79d4 100644 --- a/tests/ui/fn/fn_def_coercion.stderr +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -133,17 +133,20 @@ LL | true => foo::<&'c ()>, = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/fn_def_coercion.rs:54:5 + --> $DIR/fn_def_coercion.rs:50:18 | LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | x(b); - | ^^^^ argument requires that `'b` must outlive `'a` +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance help: the following changes may resolve your lifetime errors | diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr index 2084697e7e26d..1478ad1431ba4 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -4,11 +4,9 @@ error[E0597]: `c` does not live long enough LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'static u32>; + | -------------------------- assignment requires that `c` is borrowed for `'static` LL | f(&c); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'static` + | ^^ borrowed value does not live long enough LL | } | - `c` dropped here while still borrowed @@ -20,11 +18,9 @@ LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; + | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ^^ borrowed value does not live long enough LL | } | - `c` dropped here while still borrowed @@ -37,11 +33,9 @@ LL | let _closure = || { LL | let c = 66; | - binding `c` declared here LL | let f = SomeStruct::<&'a u32>; + | --------------------- assignment requires that `c` is borrowed for `'a` LL | f(&c); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `c` is borrowed for `'a` + | ^^ borrowed value does not live long enough LL | }; | - `c` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index c42ea0172cf75..087e270c70f7d 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -4,11 +4,10 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... +LL | let x = <&'static u32 as Bazoom<_>>::method; + | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | --^^------- - | | | - | | borrowed value does not live long enough - | argument requires that `a` is borrowed for `'static` + | ^^ borrowed value does not live long enough LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index 287337c7d52d3..c89bed3b1b18f 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -4,11 +4,10 @@ error[E0597]: `a` does not live long enough LL | let a = 22; | - binding `a` declared here ... +LL | let x = <&'static u32 as Bazoom<_>>::method; + | ----------------------------------- assignment requires that `a` is borrowed for `'static` LL | x(&a, b, c); - | --^^------- - | | | - | | borrowed value does not live long enough - | argument requires that `a` is borrowed for `'static` + | ^^ borrowed value does not live long enough LL | } | - `a` dropped here while still borrowed diff --git a/tests/ui/nll/user-annotations/promoted-annotation.stderr b/tests/ui/nll/user-annotations/promoted-annotation.stderr index 39993475796f5..ca99e53187091 100644 --- a/tests/ui/nll/user-annotations/promoted-annotation.stderr +++ b/tests/ui/nll/user-annotations/promoted-annotation.stderr @@ -6,11 +6,9 @@ LL | fn foo<'a>() { LL | let x = 0; | - binding `x` declared here LL | let f = &drop::<&'a i32>; + | ---------------- assignment requires that `x` is borrowed for `'a` LL | f(&x); - | --^^- - | | | - | | borrowed value does not live long enough - | argument requires that `x` is borrowed for `'a` + | ^^ borrowed value does not live long enough LL | LL | } | - `x` dropped here while still borrowed From af15e048b209e98d8dfc5122129b49cd40524a0a Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Tue, 7 Jan 2025 09:18:31 +0530 Subject: [PATCH 078/189] Reserve x18 register for aarch64 wrs vxworks target --- compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs index d5e78d0307606..ac53cbaecceb1 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { - features: "+v8a".into(), + features: "+v8a,+reserve-x18".into(), max_atomic_width: Some(128), stack_probes: StackProbeType::Inline, ..base::vxworks::opts() From 7b801a845429abcdc966def8f2865e7a65188d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:23:25 +0800 Subject: [PATCH 079/189] triagebot: adjust some test suite tool autolabels --- triagebot.toml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 2a0ad610c1a00..a83b119c00507 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -414,13 +414,20 @@ trigger_files = [ [autolabel."A-testsuite"] trigger_files = [ + "src/bootstrap/src/core/build_steps/test.rs", "src/ci", - "src/tools/compiletest", "src/tools/cargotest", - "src/tools/tidy", + "src/tools/compiletest", + "src/tools/miropt-test-tools", "src/tools/remote-test-server", "src/tools/remote-test-client", - "src/tools/tier-check" + "src/tools/rustdoc-gui-test", + "src/tools/suggest-tests", +] + +[autolabel."A-tidy"] +trigger_files = [ + "src/tools/tidy", ] [autolabel."A-meta"] From 427abb69bf4c788504fa454fa03559e815c682df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jan 2025 15:38:44 +0100 Subject: [PATCH 080/189] arm: add unstable soft-float target feature --- compiler/rustc_target/src/target_features.rs | 8 ++++++++ tests/ui/check-cfg/target_feature.stderr | 1 + 2 files changed, 9 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f594d20f9286f..9fd07c8634aa1 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -148,6 +148,11 @@ const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("neon", Unstable(sym::arm_target_feature), &["vfp3"]), ("rclass", Unstable(sym::arm_target_feature), &[]), ("sha2", Unstable(sym::arm_target_feature), &["neon"]), + // This can be *disabled* on non-`hf` targets to enable the use + // of hardfloats while keeping the softfloat ABI. + // FIXME before stabilization: Should we expose this as a `hard-float` target feature instead of + // matching the odd negative feature LLVM uses? + ("soft-float", Unstable(sym::arm_target_feature), &[]), // This is needed for inline assembly, but shouldn't be stabilized as-is // since it should be enabled per-function using #[instruction_set], not // #[target_feature]. @@ -790,6 +795,9 @@ impl Target { match self.llvm_floatabi.unwrap() { FloatAbi::Soft => { // Nothing special required, will use soft-float ABI throughout. + // We can even allow `-soft-float` here; in fact that is useful as it lets + // people use FPU instructions with a softfloat ABI (corresponds to + // `-mfloat-abi=softfp` in GCC/clang). NOTHING } FloatAbi::Hard => { diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 70fec8a350aa1..bf54d17f6ec8a 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -202,6 +202,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `sme-lutv2` `sme2` `sme2p1` +`soft-float` `spe` `ssbs` `sse` From a28b98650ffc7681aa388011055761c64eb5f3c9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:19:40 +0000 Subject: [PATCH 081/189] Remove a couple of obsolete tests mod_bench is basically useless as test and hasn't been used as benchmark for a long time. alloc_example doesn't test anything that isn't already tested by std_example. --- build_system/tests.rs | 3 - config.txt | 3 - example/alloc_example.rs | 44 -------------- example/alloc_system.rs | 124 --------------------------------------- example/mod_bench.rs | 37 ------------ 5 files changed, 211 deletions(-) delete mode 100644 example/alloc_example.rs delete mode 100644 example/alloc_system.rs delete mode 100644 example/mod_bench.rs diff --git a/build_system/tests.rs b/build_system/tests.rs index 08736db8ba0c8..8de419a0c4eb2 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -73,8 +73,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ "example/arbitrary_self_types_pointers_and_wrappers.rs", &[], ), - TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"), - TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]), TestCase::jit_bin("jit.std_example", "example/std_example.rs", "arg"), TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]), TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]), @@ -89,7 +87,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ &[], ), TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]), - TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]), TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]), TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"), TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]), diff --git a/config.txt b/config.txt index 9808ad624e11c..f578cbef35e68 100644 --- a/config.txt +++ b/config.txt @@ -21,15 +21,12 @@ aot.mini_core_hello_world testsuite.base_sysroot aot.arbitrary_self_types_pointers_and_wrappers aot.issue_91827_extern_types -build.alloc_system -aot.alloc_example jit.std_example aot.std_example aot.dst_field_align aot.subslice-patterns-const-eval aot.track-caller-attribute aot.float-minmax-pass -aot.mod_bench aot.issue-72793 aot.issue-59326 aot.neon diff --git a/example/alloc_example.rs b/example/alloc_example.rs deleted file mode 100644 index da70ca7943983..0000000000000 --- a/example/alloc_example.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] -#![allow(internal_features)] -#![no_std] - -extern crate alloc; -extern crate alloc_system; - -use alloc::boxed::Box; - -use alloc_system::System; - -#[global_allocator] -static ALLOC: System = System; - -#[cfg_attr(unix, link(name = "c"))] -#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] -extern "C" { - fn puts(s: *const u8) -> i32; -} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { - core::intrinsics::abort(); -} - -#[alloc_error_handler] -fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { - core::intrinsics::abort(); -} - -#[lang = "eh_personality"] -fn eh_personality() -> ! { - loop {} -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - let world: Box<&str> = Box::new("Hello World!\0"); - unsafe { - puts(*world as *const str as *const u8); - } - - 0 -} diff --git a/example/alloc_system.rs b/example/alloc_system.rs deleted file mode 100644 index 2884c9c32ae4d..0000000000000 --- a/example/alloc_system.rs +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org) - -#![no_std] - -pub struct System; - -#[cfg(any(windows, unix, target_os = "redox"))] -mod realloc_fallback { - use core::alloc::{GlobalAlloc, Layout}; - use core::{cmp, ptr}; - impl super::System { - pub(crate) unsafe fn realloc_fallback( - &self, - ptr: *mut u8, - old_layout: Layout, - new_size: usize, - ) -> *mut u8 { - // Docs for GlobalAlloc::realloc require this to be valid: - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - let new_ptr = GlobalAlloc::alloc(self, new_layout); - if !new_ptr.is_null() { - let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - GlobalAlloc::dealloc(self, ptr, old_layout); - } - new_ptr - } - } -} -#[cfg(any(unix, target_os = "redox"))] -mod platform { - use core::alloc::{GlobalAlloc, Layout}; - use core::ffi::c_void; - use core::ptr; - - use System; - extern "C" { - fn posix_memalign(memptr: *mut *mut c_void, align: usize, size: usize) -> i32; - fn free(p: *mut c_void); - } - unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - aligned_malloc(&layout) - } - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - let ptr = self.alloc(layout.clone()); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } - ptr - } - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - free(ptr as *mut c_void) - } - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - self.realloc_fallback(ptr, layout, new_size) - } - } - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - let ret = posix_memalign(&mut out, layout.align(), layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } - } -} -#[cfg(windows)] -#[allow(nonstandard_style)] -mod platform { - use core::alloc::{GlobalAlloc, Layout}; - - use System; - type LPVOID = *mut u8; - type HANDLE = LPVOID; - type SIZE_T = usize; - type DWORD = u32; - type BOOL = i32; - extern "system" { - fn GetProcessHeap() -> HANDLE; - fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; - fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; - fn GetLastError() -> DWORD; - } - #[repr(C)] - struct Header(*mut u8); - const HEAP_ZERO_MEMORY: DWORD = 0x00000008; - unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { - &mut *(ptr as *mut Header).sub(1) - } - unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { - let aligned = ptr.add(align - (ptr as usize & (align - 1))); - *get_header(aligned) = Header(ptr); - aligned - } - #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { - let size = layout.size() + layout.align(); - let ptr = HeapAlloc(GetProcessHeap(), flags, size); - (if ptr.is_null() { ptr } else { align_ptr(ptr, layout.align()) }) as *mut u8 - } - unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - allocate_with_flags(layout, 0) - } - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - allocate_with_flags(layout, HEAP_ZERO_MEMORY) - } - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - let header = get_header(ptr); - let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); - debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); - } - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - self.realloc_fallback(ptr, layout, new_size) - } - } -} diff --git a/example/mod_bench.rs b/example/mod_bench.rs deleted file mode 100644 index 11a3e8fc72d8d..0000000000000 --- a/example/mod_bench.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![feature(start, core_intrinsics, lang_items)] -#![allow(internal_features)] -#![no_std] - -#[cfg_attr(unix, link(name = "c"))] -#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] -extern "C" {} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { - core::intrinsics::abort(); -} - -#[lang = "eh_personality"] -fn eh_personality() {} - -// Required for rustc_codegen_llvm -#[no_mangle] -unsafe extern "C" fn _Unwind_Resume() { - core::intrinsics::unreachable(); -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - for i in 2..10_000_000 { - black_box((i + 1) % i); - } - - 0 -} - -#[inline(never)] -fn black_box(i: u32) { - if i != 1 { - core::intrinsics::abort(); - } -} From 0335dc131fb35f710668f6e079d39eebbc31edac Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:38:44 +0000 Subject: [PATCH 082/189] Make TimingGuard a little safer --- src/driver/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/driver/mod.rs b/src/driver/mod.rs index fb0eed07c1971..ffd47cace3807 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -73,12 +73,14 @@ impl Drop for TimingGuard { impl cranelift_codegen::timing::Profiler for MeasuremeProfiler { fn start_pass(&self, pass: cranelift_codegen::timing::Pass) -> Box { - let mut timing_guard = - TimingGuard { profiler: std::mem::ManuallyDrop::new(self.0.clone()), inner: None }; + let mut timing_guard = Box::new(TimingGuard { + profiler: std::mem::ManuallyDrop::new(self.0.clone()), + inner: None, + }); timing_guard.inner = Some( unsafe { &*(&*timing_guard.profiler as &SelfProfilerRef as *const SelfProfilerRef) } .generic_activity(pass.description()), ); - Box::new(timing_guard) + timing_guard } } From 8ecd033654667f283cd7295ac532de92898bf301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 29 Dec 2024 18:42:33 +0100 Subject: [PATCH 083/189] Rename CI script from `calculate-job-matrix` to `ci.py` --- .github/workflows/ci.yml | 4 ++-- src/ci/github-actions/{calculate-job-matrix.py => ci.py} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/ci/github-actions/{calculate-job-matrix.py => ci.py} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0e151d25778c..bedfe72137c81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ # and also on pushes to special branches (auto, try). # # The actual definition of the executed jobs is calculated by a Python -# script located at src/ci/github-actions/calculate-job-matrix.py, which +# script located at src/ci/github-actions/ci.py, which # uses job definition data from src/ci/github-actions/jobs.yml. # You should primarily modify the `jobs.yml` file if you want to modify # what jobs are executed in CI. @@ -56,7 +56,7 @@ jobs: - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT + run: python3 src/ci/github-actions/ci.py >> $GITHUB_OUTPUT id: jobs job: name: ${{ matrix.name }} diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/ci.py similarity index 100% rename from src/ci/github-actions/calculate-job-matrix.py rename to src/ci/github-actions/ci.py From 0cc11f8c480cce40859ecb82fd8db54771b6aba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 29 Dec 2024 19:15:36 +0100 Subject: [PATCH 084/189] Add a command to run a given Linux CI job locally --- .github/workflows/ci.yml | 2 +- src/ci/github-actions/ci.py | 86 +++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bedfe72137c81..d8d7560ffcf41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - run: python3 src/ci/github-actions/ci.py >> $GITHUB_OUTPUT + run: python3 src/ci/github-actions/ci.py calculate-job-matrix >> $GITHUB_OUTPUT id: jobs job: name: ${{ matrix.name }} diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py index 1f994f0ffd2ef..354c0f4844a28 100755 --- a/src/ci/github-actions/ci.py +++ b/src/ci/github-actions/ci.py @@ -1,18 +1,20 @@ #!/usr/bin/env python3 """ -This script serves for generating a matrix of jobs that should -be executed on CI. +This script contains CI functionality. +It can be used to generate a matrix of jobs that should +be executed on CI, or run a specific CI job locally. -It reads job definitions from `src/ci/github-actions/jobs.yml` -and filters them based on the event that happened on CI. +It reads job definitions from `src/ci/github-actions/jobs.yml`. """ +import argparse import dataclasses import json import logging import os import re +import subprocess import typing from pathlib import Path from typing import List, Dict, Any, Optional @@ -181,30 +183,76 @@ def format_run_type(run_type: WorkflowRunType) -> str: raise AssertionError() +def run_workflow_locally(job_data: Dict[str, Any], job_name: str): + DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker" + + jobs = list(job_data["auto"]) + jobs.extend(job_data["pr"]) + + jobs = [job for job in jobs if job.get("image") == job_name] + if len(jobs) == 0: + raise Exception(f"Job `{job_name}` not found") + job = jobs[0] + if "ubuntu" not in job["os"]: + raise Exception("Only Linux jobs can be executed locally") + + image = job.get("env", {}).get("IMAGE", job["image"]) + custom_env = {} + custom_env["DEPLOY"] = "1" + custom_env.update({k: str(v) for (k, v) in job.get("env", {}).items()}) + + args = [ + str(DOCKER_DIR / "run.sh"), + image + ] + env_formatted = [f"{k}={v}" for (k, v) in sorted(custom_env.items())] + print(f"Executing `{' '.join(env_formatted)} {' '.join(args)}`") + + env = os.environ.copy() + env.update(custom_env) + subprocess.run(args, env=env) + + if __name__ == "__main__": logging.basicConfig(level=logging.INFO) with open(JOBS_YAML_PATH) as f: data = yaml.safe_load(f) - github_ctx = get_github_ctx() + parser = argparse.ArgumentParser( + prog="ci.py", + description="Generate or run CI workflows" + ) + generate_matrix = argparse.ArgumentParser() + subparsers = parser.add_subparsers(help="Command to execute", dest="command", required=True) + subparsers.add_parser("calculate-job-matrix") + run_parser = subparsers.add_parser("run-local") + run_parser.add_argument("job_name", help="CI job that should be executed") + args = parser.parse_args() - run_type = find_run_type(github_ctx) - logging.info(f"Job type: {run_type}") + if args.command == "calculate-job-matrix": + github_ctx = get_github_ctx() - with open(CI_DIR / "channel") as f: - channel = f.read().strip() + run_type = find_run_type(github_ctx) + logging.info(f"Job type: {run_type}") - jobs = [] - if run_type is not None: - jobs = calculate_jobs(run_type, data) - jobs = skip_jobs(jobs, channel) + with open(CI_DIR / "channel") as f: + channel = f.read().strip() - if not jobs: - raise Exception("Scheduled job list is empty, this is an error") + jobs = [] + if run_type is not None: + jobs = calculate_jobs(run_type, data) + jobs = skip_jobs(jobs, channel) - run_type = format_run_type(run_type) + if not jobs: + raise Exception("Scheduled job list is empty, this is an error") - logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") - print(f"jobs={json.dumps(jobs)}") - print(f"run_type={run_type}") + run_type = format_run_type(run_type) + + logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") + print(f"jobs={json.dumps(jobs)}") + print(f"run_type={run_type}") + elif args.command == "run-local": + run_workflow_locally(data, args.job_name) + else: + raise Exception(f"Unknown command {args.command}") From e4b6ccef43133bae1e2396f3375aaeeb799461ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 29 Dec 2024 19:20:39 +0100 Subject: [PATCH 085/189] Update documentation --- src/ci/docker/README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 508b7b40c01e4..2f52ff5a99a50 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -1,29 +1,30 @@ # Docker images for CI This folder contains a bunch of docker images used by the continuous integration -(CI) of Rust. An script is accompanied (`run.sh`) with these images to actually -execute them. To test out an image execute: +(CI) of Rust. A script is accompanied (`run.sh`) with these images to actually +execute them. -``` -./src/ci/docker/run.sh $image_name -``` +Note that a single Docker image can be used by multiple CI jobs, so the job name +is the important thing that you should know. You can examine the existing CI jobs in +the [`jobs.yml`](../github-actions/jobs.yml) file. -for example: +To run a specific CI job locally, you can use the following script: ``` -./src/ci/docker/run.sh x86_64-gnu +python3 ./src/ci/github-actions/ci.py run-local ``` -Images will output artifacts in an `obj/$image_name` dir at the root of a repository. Note -that the script will overwrite the contents of this directory. - -To match conditions in rusts CI, also set the environment variable `DEPLOY=1`, e.g.: +For example, to run the `x86_64-gnu-llvm-18-1` job: ``` -DEPLOY=1 ./src/ci/docker/run.sh x86_64-gnu +python3 ./src/ci/github-actions/ci.py run-local x86_64-gnu-llvm-18-1 ``` +The job will output artifacts in an `obj/` dir at the root of a repository. Note +that the script will overwrite the contents of this directory. `` is set based on the +Docker image executed in the given CI job. + **NOTE**: In CI, the script outputs the artifacts to the `obj` directory, -while locally, to the `obj/$image_name` directory. This is primarily to prevent +while locally, to the `obj/` directory. This is primarily to prevent strange linker errors when using multiple Docker images. For some Linux workflows (for example `x86_64-gnu-llvm-18-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-18-3` workflow, you can run the following script: From e62d1e46bbc4660ae5ec64c7e9f18244bf3f93b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 29 Dec 2024 22:52:45 +0100 Subject: [PATCH 086/189] Rename `image` property of CI jobs to `name` The `image` part didn't really make sense, especially since we started splitting CI jobs. --- src/ci/github-actions/ci.py | 34 +++++--- src/ci/github-actions/jobs.yml | 146 ++++++++++++++++----------------- 2 files changed, 96 insertions(+), 84 deletions(-) diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py index 354c0f4844a28..4ec4cf11b5bac 100755 --- a/src/ci/github-actions/ci.py +++ b/src/ci/github-actions/ci.py @@ -27,13 +27,18 @@ Job = Dict[str, Any] -def name_jobs(jobs: List[Dict], prefix: str) -> List[Job]: +def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]: """ - Add a `name` attribute to each job, based on its image and the given `prefix`. + Modify the `name` attribute of each job, based on its base name and the given `prefix`. + Add an `image` attribute to each job, base don its image. """ + modified_jobs = [] for job in jobs: - job["name"] = f"{prefix} - {job['image']}" - return jobs + job = dict(job) + job["image"] = get_job_image(job) + job["name"] = f"{prefix} - {job['name']}" + modified_jobs.append(job) + return modified_jobs def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]: @@ -118,7 +123,7 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]: if isinstance(run_type, PRRunType): - return add_base_env(name_jobs(job_data["pr"], "PR"), job_data["envs"]["pr"]) + return add_base_env(add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"]) elif isinstance(run_type, TryRunType): jobs = job_data["try"] custom_jobs = run_type.custom_jobs @@ -132,7 +137,7 @@ def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[ jobs = [] unknown_jobs = [] for custom_job in custom_jobs: - job = [j for j in job_data["auto"] if j["image"] == custom_job] + job = [j for j in job_data["auto"] if j["name"] == custom_job] if not job: unknown_jobs.append(custom_job) continue @@ -142,10 +147,10 @@ def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[ f"Custom job(s) `{unknown_jobs}` not found in auto jobs" ) - return add_base_env(name_jobs(jobs, "try"), job_data["envs"]["try"]) + return add_base_env(add_job_properties(jobs, "try"), job_data["envs"]["try"]) elif isinstance(run_type, AutoRunType): return add_base_env( - name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"] + add_job_properties(job_data["auto"], "auto"), job_data["envs"]["auto"] ) return [] @@ -183,27 +188,34 @@ def format_run_type(run_type: WorkflowRunType) -> str: raise AssertionError() +def get_job_image(job) -> str: + """ + By default, the Docker image of a job is based on its name. + However, it can be overridden by its IMAGE environment variable. + """ + return job.get("env", {}).get("IMAGE", job["name"]) + + def run_workflow_locally(job_data: Dict[str, Any], job_name: str): DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker" jobs = list(job_data["auto"]) jobs.extend(job_data["pr"]) - jobs = [job for job in jobs if job.get("image") == job_name] + jobs = [job for job in jobs if job.get("name") == job_name] if len(jobs) == 0: raise Exception(f"Job `{job_name}` not found") job = jobs[0] if "ubuntu" not in job["os"]: raise Exception("Only Linux jobs can be executed locally") - image = job.get("env", {}).get("IMAGE", job["image"]) custom_env = {} custom_env["DEPLOY"] = "1" custom_env.update({k: str(v) for (k, v) in job.get("env", {}).items()}) args = [ str(DOCKER_DIR / "run.sh"), - image + get_job_image(job) ] env_formatted = [f"{k}={v}" for (k, v) in sorted(custom_env.items())] print(f"Executing `{' '.join(env_formatted)} {' '.join(args)}`") diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 876a779359215..d88be6543a3d0 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -91,26 +91,26 @@ envs: # These jobs automatically inherit envs.pr, to avoid repeating # it in each job definition. pr: - - image: mingw-check + - name: mingw-check <<: *job-linux-4c - - image: mingw-check-tidy + - name: mingw-check-tidy continue_on_error: true <<: *job-linux-4c - - image: x86_64-gnu-llvm-18 + - name: x86_64-gnu-llvm-18 env: ENABLE_GCC_CODEGEN: "1" # We are adding (temporarily) a dummy commit on the compiler READ_ONLY_SRC: "0" DOCKER_SCRIPT: x86_64-gnu-llvm.sh <<: *job-linux-16c - - image: x86_64-gnu-tools + - name: x86_64-gnu-tools <<: *job-linux-16c # Jobs that run when you perform a try build (@bors try) # These jobs automatically inherit envs.try, to avoid repeating # it in each job definition. try: - - image: dist-x86_64-linux + - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-16c @@ -123,106 +123,106 @@ auto: # Linux/Docker builders # ############################# - - image: aarch64-gnu + - name: aarch64-gnu <<: *job-aarch64-linux - - image: aarch64-gnu-debug + - name: aarch64-gnu-debug <<: *job-aarch64-linux - - image: arm-android + - name: arm-android <<: *job-linux-4c - - image: armhf-gnu + - name: armhf-gnu <<: *job-linux-4c - - image: dist-aarch64-linux + - name: dist-aarch64-linux env: CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-4c - - image: dist-android + - name: dist-android <<: *job-linux-4c - - image: dist-arm-linux + - name: dist-arm-linux <<: *job-linux-8c - - image: dist-armhf-linux + - name: dist-armhf-linux <<: *job-linux-4c - - image: dist-armv7-linux + - name: dist-armv7-linux <<: *job-linux-4c - - image: dist-i586-gnu-i586-i686-musl + - name: dist-i586-gnu-i586-i686-musl <<: *job-linux-4c - - image: dist-i686-linux + - name: dist-i686-linux <<: *job-linux-4c - - image: dist-loongarch64-linux + - name: dist-loongarch64-linux <<: *job-linux-4c - - image: dist-loongarch64-musl + - name: dist-loongarch64-musl <<: *job-linux-4c - - image: dist-ohos + - name: dist-ohos <<: *job-linux-4c - - image: dist-powerpc-linux + - name: dist-powerpc-linux <<: *job-linux-4c - - image: dist-powerpc64-linux + - name: dist-powerpc64-linux <<: *job-linux-4c - - image: dist-powerpc64le-linux + - name: dist-powerpc64le-linux <<: *job-linux-4c-largedisk - - image: dist-riscv64-linux + - name: dist-riscv64-linux <<: *job-linux-4c - - image: dist-s390x-linux + - name: dist-s390x-linux <<: *job-linux-4c - - image: dist-various-1 + - name: dist-various-1 <<: *job-linux-4c - - image: dist-various-2 + - name: dist-various-2 <<: *job-linux-4c - - image: dist-x86_64-freebsd + - name: dist-x86_64-freebsd <<: *job-linux-4c - - image: dist-x86_64-illumos + - name: dist-x86_64-illumos <<: *job-linux-4c - - image: dist-x86_64-linux + - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-16c - - image: dist-x86_64-linux-alt + - name: dist-x86_64-linux-alt env: IMAGE: dist-x86_64-linux CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-16c - - image: dist-x86_64-musl + - name: dist-x86_64-musl env: CODEGEN_BACKENDS: llvm,cranelift <<: *job-linux-4c - - image: dist-x86_64-netbsd + - name: dist-x86_64-netbsd <<: *job-linux-4c # The i686-gnu job is split into multiple jobs to run tests in parallel. # i686-gnu-1 skips tests that run in i686-gnu-2. - - image: i686-gnu-1 + - name: i686-gnu-1 env: IMAGE: i686-gnu DOCKER_SCRIPT: stage_2_test_set1.sh <<: *job-linux-4c # Skip tests that run in i686-gnu-1 - - image: i686-gnu-2 + - name: i686-gnu-2 env: IMAGE: i686-gnu DOCKER_SCRIPT: stage_2_test_set2.sh @@ -230,14 +230,14 @@ auto: # The i686-gnu-nopt job is split into multiple jobs to run tests in parallel. # i686-gnu-nopt-1 skips tests that run in i686-gnu-nopt-2 - - image: i686-gnu-nopt-1 + - name: i686-gnu-nopt-1 env: IMAGE: i686-gnu-nopt DOCKER_SCRIPT: /scripts/stage_2_test_set1.sh <<: *job-linux-4c # Skip tests that run in i686-gnu-nopt-1 - - image: i686-gnu-nopt-2 + - name: i686-gnu-nopt-2 env: IMAGE: i686-gnu-nopt DOCKER_SCRIPT: >- @@ -245,13 +245,13 @@ auto: /scripts/stage_2_test_set2.sh <<: *job-linux-4c - - image: mingw-check + - name: mingw-check <<: *job-linux-4c - - image: test-various + - name: test-various <<: *job-linux-4c - - image: x86_64-fuchsia + - name: x86_64-fuchsia # Only run this job on the nightly channel. Fuchsia requires # nightly features to compile, and this job would fail if # executed on beta and stable. @@ -260,10 +260,10 @@ auto: # Tests integration with Rust for Linux. # Builds stage 1 compiler and tries to compile a few RfL examples with it. - - image: x86_64-rust-for-linux + - name: x86_64-rust-for-linux <<: *job-linux-4c - - image: x86_64-gnu + - name: x86_64-gnu <<: *job-linux-4c # This job ensures commits landing on nightly still pass the full @@ -271,7 +271,7 @@ auto: # depend on the channel being built (for example if they include the # channel name on the output), and this builder prevents landing # changes that would result in broken builds after a promotion. - - image: x86_64-gnu-stable + - name: x86_64-gnu-stable # Only run this job on the nightly channel. Running this on beta # could cause failures when `dev: 1` in `stage0.txt`, and running # this on stable is useless. @@ -281,20 +281,20 @@ auto: RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable <<: *job-linux-4c - - image: x86_64-gnu-aux + - name: x86_64-gnu-aux <<: *job-linux-4c - - image: x86_64-gnu-debug + - name: x86_64-gnu-debug # This seems to be needed because a full stage 2 build + run-make tests # overwhelms the storage capacity of the standard 4c runner. <<: *job-linux-4c-largedisk - - image: x86_64-gnu-distcheck + - name: x86_64-gnu-distcheck <<: *job-linux-8c # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}. - - image: x86_64-gnu-llvm-19-1 + - name: x86_64-gnu-llvm-19-1 env: RUST_BACKTRACE: 1 IMAGE: x86_64-gnu-llvm-19 @@ -302,7 +302,7 @@ auto: <<: *job-linux-4c # Skip tests that run in x86_64-gnu-llvm-19-{1,3} - - image: x86_64-gnu-llvm-19-2 + - name: x86_64-gnu-llvm-19-2 env: RUST_BACKTRACE: 1 IMAGE: x86_64-gnu-llvm-19 @@ -310,7 +310,7 @@ auto: <<: *job-linux-4c # Skip tests that run in x86_64-gnu-llvm-19-{1,2} - - image: x86_64-gnu-llvm-19-3 + - name: x86_64-gnu-llvm-19-3 env: RUST_BACKTRACE: 1 IMAGE: x86_64-gnu-llvm-19 @@ -319,7 +319,7 @@ auto: # The x86_64-gnu-llvm-18 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-18-1 skips tests that run in x86_64-gnu-llvm-18-{2,3}. - - image: x86_64-gnu-llvm-18-1 + - name: x86_64-gnu-llvm-18-1 env: RUST_BACKTRACE: 1 READ_ONLY_SRC: "0" @@ -328,7 +328,7 @@ auto: <<: *job-linux-4c # Skip tests that run in x86_64-gnu-llvm-18-{1,3} - - image: x86_64-gnu-llvm-18-2 + - name: x86_64-gnu-llvm-18-2 env: RUST_BACKTRACE: 1 READ_ONLY_SRC: "0" @@ -337,7 +337,7 @@ auto: <<: *job-linux-4c # Skip tests that run in x86_64-gnu-llvm-18-{1,2} - - image: x86_64-gnu-llvm-18-3 + - name: x86_64-gnu-llvm-18-3 env: RUST_BACKTRACE: 1 READ_ONLY_SRC: "0" @@ -345,10 +345,10 @@ auto: DOCKER_SCRIPT: x86_64-gnu-llvm3.sh <<: *job-linux-4c - - image: x86_64-gnu-nopt + - name: x86_64-gnu-nopt <<: *job-linux-4c - - image: x86_64-gnu-tools + - name: x86_64-gnu-tools env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-4c @@ -357,7 +357,7 @@ auto: # macOS Builders # #################### - - image: dist-x86_64-apple + - name: dist-x86_64-apple env: SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 @@ -371,7 +371,7 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos-xl - - image: dist-apple-various + - name: dist-apple-various env: SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim,aarch64-apple-ios-macabi,x86_64-apple-ios-macabi # Mac Catalyst cannot currently compile the sanitizer: @@ -385,19 +385,19 @@ auto: NO_OVERFLOW_CHECKS: 1 <<: *job-macos-xl - - image: x86_64-apple-1 + - name: x86_64-apple-1 env: <<: *env-x86_64-apple-tests <<: *job-macos-xl - - image: x86_64-apple-2 + - name: x86_64-apple-2 env: SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc <<: *env-x86_64-apple-tests <<: *job-macos-xl # This target only needs to support 11.0 and up as nothing else supports the hardware - - image: dist-aarch64-apple + - name: dist-aarch64-apple env: SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin RUST_CONFIGURE_ARGS: >- @@ -421,7 +421,7 @@ auto: <<: *job-macos-m1 # This target only needs to support 11.0 and up as nothing else supports the hardware - - image: aarch64-apple + - name: aarch64-apple env: SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin RUST_CONFIGURE_ARGS: >- @@ -442,20 +442,20 @@ auto: # Windows Builders # ###################### - - image: x86_64-msvc + - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: make ci-msvc <<: *job-windows-8c - - image: i686-msvc + - name: i686-msvc env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make ci-msvc <<: *job-windows-8c # x86_64-msvc-ext is split into multiple jobs to run tests in parallel. - - image: x86_64-msvc-ext1 + - name: x86_64-msvc-ext1 env: SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld @@ -464,7 +464,7 @@ auto: # Temporary builder to workaround CI issues # See #FIXME: Remove this, and re-enable the same tests in `checktools.sh`, once CI issues are fixed. - - image: x86_64-msvc-ext2 + - name: x86_64-msvc-ext2 env: SCRIPT: > python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass && @@ -476,7 +476,7 @@ auto: <<: *job-windows # Run `checktools.sh` and upload the toolstate file. - - image: x86_64-msvc-ext3 + - name: x86_64-msvc-ext3 env: SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows HOST_TARGET: x86_64-pc-windows-msvc @@ -500,7 +500,7 @@ auto: # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - image: i686-mingw + - name: i686-mingw env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw @@ -510,7 +510,7 @@ auto: <<: *job-windows-8c # x86_64-mingw is split into two jobs to run tests in parallel. - - image: x86_64-mingw-1 + - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-x RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu @@ -519,7 +519,7 @@ auto: NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows - - image: x86_64-mingw-2 + - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-bootstrap RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu @@ -528,7 +528,7 @@ auto: NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows - - image: dist-x86_64-msvc + - name: dist-x86_64-msvc env: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc @@ -542,7 +542,7 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows-8c - - image: dist-i686-msvc + - name: dist-i686-msvc env: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc @@ -555,7 +555,7 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows - - image: dist-aarch64-msvc + - name: dist-aarch64-msvc env: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc @@ -567,7 +567,7 @@ auto: DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows - - image: dist-i686-mingw + - name: dist-i686-mingw env: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-gnu @@ -580,7 +580,7 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows - - image: dist-x86_64-mingw + - name: dist-x86_64-mingw env: SCRIPT: python x.py dist bootstrap --include-default-paths RUST_CONFIGURE_ARGS: >- @@ -593,7 +593,7 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows - - image: dist-x86_64-msvc-alt + - name: dist-x86_64-msvc-alt env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths From 0fc2f14c0cd15cda261ca43b74b2495656df6dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 31 Dec 2024 10:18:02 +0100 Subject: [PATCH 087/189] Make it possible to select PR vs auto jobs --- src/ci/github-actions/ci.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py index 4ec4cf11b5bac..d1c665503b1d1 100755 --- a/src/ci/github-actions/ci.py +++ b/src/ci/github-actions/ci.py @@ -30,7 +30,7 @@ def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]: """ Modify the `name` attribute of each job, based on its base name and the given `prefix`. - Add an `image` attribute to each job, base don its image. + Add an `image` attribute to each job, based on its image. """ modified_jobs = [] for job in jobs: @@ -196,15 +196,14 @@ def get_job_image(job) -> str: return job.get("env", {}).get("IMAGE", job["name"]) -def run_workflow_locally(job_data: Dict[str, Any], job_name: str): +def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool): DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker" - jobs = list(job_data["auto"]) - jobs.extend(job_data["pr"]) - + jobs = job_data["pr"] if pr_jobs else job_data["auto"] jobs = [job for job in jobs if job.get("name") == job_name] if len(jobs) == 0: - raise Exception(f"Job `{job_name}` not found") + raise Exception(f"Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs") + assert len(jobs) == 1 job = jobs[0] if "ubuntu" not in job["os"]: raise Exception("Only Linux jobs can be executed locally") @@ -222,7 +221,12 @@ def run_workflow_locally(job_data: Dict[str, Any], job_name: str): env = os.environ.copy() env.update(custom_env) - subprocess.run(args, env=env) + + process = subprocess.Popen(args, env=env) + try: + process.wait() + except KeyboardInterrupt: + process.kill() if __name__ == "__main__": @@ -239,7 +243,16 @@ def run_workflow_locally(job_data: Dict[str, Any], job_name: str): subparsers = parser.add_subparsers(help="Command to execute", dest="command", required=True) subparsers.add_parser("calculate-job-matrix") run_parser = subparsers.add_parser("run-local") - run_parser.add_argument("job_name", help="CI job that should be executed") + run_parser.add_argument( + "job_name", + help="CI job that should be executed. By default, a merge (auto) " + "job with the given name will be executed" + ) + run_parser.add_argument( + "--pr", + action="store_true", + help="Run a PR job instead of an auto job" + ) args = parser.parse_args() if args.command == "calculate-job-matrix": @@ -265,6 +278,6 @@ def run_workflow_locally(job_data: Dict[str, Any], job_name: str): print(f"jobs={json.dumps(jobs)}") print(f"run_type={run_type}") elif args.command == "run-local": - run_workflow_locally(data, args.job_name) + run_workflow_locally(data, args.job_name, args.pr) else: raise Exception(f"Unknown command {args.command}") From 56cba09d1ea05056694cf1b57e9337cb16d1d9d7 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 7 Jan 2025 19:02:24 +0100 Subject: [PATCH 088/189] Remove outdated information in the `unreachable_pub` lint description --- compiler/rustc_lint/src/builtin.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e74fb9d92e9e0..ba4b786aca218 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1271,9 +1271,8 @@ declare_lint! { /// `pub(crate)` visibility is recommended to be used instead. This more clearly expresses the /// intent that the item is only visible within its own crate. /// - /// This lint is "allow" by default because it will trigger for a large - /// amount of existing Rust code, and has some false-positives. Eventually it - /// is desired for this to become warn-by-default. + /// This lint is "allow" by default because it will trigger for a large amount of existing Rust code. + /// Eventually it is desired for this to become warn-by-default. /// /// [`unnameable_types`]: #unnameable-types pub UNREACHABLE_PUB, From 5a95dda44ab42d4d2cdb199a2fa9ac8ba1d7a3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 7 Jan 2025 18:40:08 +0100 Subject: [PATCH 089/189] Apply review comments --- src/ci/github-actions/ci.py | 151 ++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 58 deletions(-) diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py index d1c665503b1d1..97539cf1cdb24 100755 --- a/src/ci/github-actions/ci.py +++ b/src/ci/github-actions/ci.py @@ -34,10 +34,11 @@ def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]: """ modified_jobs = [] for job in jobs: - job = dict(job) - job["image"] = get_job_image(job) - job["name"] = f"{prefix} - {job['name']}" - modified_jobs.append(job) + # Create a copy of the `job` dictionary to avoid modifying `jobs` + new_job = dict(job) + new_job["image"] = get_job_image(new_job) + new_job["name"] = f"{prefix} - {new_job['name']}" + modified_jobs.append(new_job) return modified_jobs @@ -46,11 +47,15 @@ def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]: Prepends `environment` to the `env` attribute of each job. The `env` of each job has higher precedence than `environment`. """ + modified_jobs = [] for job in jobs: env = environment.copy() env.update(job.get("env", {})) - job["env"] = env - return jobs + + new_job = dict(job) + new_job["env"] = env + modified_jobs.append(new_job) + return modified_jobs @dataclasses.dataclass @@ -123,7 +128,9 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]: if isinstance(run_type, PRRunType): - return add_base_env(add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"]) + return add_base_env( + add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"] + ) elif isinstance(run_type, TryRunType): jobs = job_data["try"] custom_jobs = run_type.custom_jobs @@ -188,95 +195,123 @@ def format_run_type(run_type: WorkflowRunType) -> str: raise AssertionError() -def get_job_image(job) -> str: +def get_job_image(job: Job) -> str: """ By default, the Docker image of a job is based on its name. However, it can be overridden by its IMAGE environment variable. """ - return job.get("env", {}).get("IMAGE", job["name"]) + env = job.get("env", {}) + # Return the IMAGE environment variable if it exists, otherwise return the job name + return env.get("IMAGE", job["name"]) -def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool): - DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker" +def is_linux_job(job: Job) -> bool: + return "ubuntu" in job["os"] - jobs = job_data["pr"] if pr_jobs else job_data["auto"] - jobs = [job for job in jobs if job.get("name") == job_name] + +def find_linux_job(job_data: Dict[str, Any], job_name: str, pr_jobs: bool) -> Job: + candidates = job_data["pr"] if pr_jobs else job_data["auto"] + jobs = [job for job in candidates if job.get("name") == job_name] if len(jobs) == 0: - raise Exception(f"Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs") + available_jobs = "\n".join( + sorted(job["name"] for job in candidates if is_linux_job(job)) + ) + raise Exception(f"""Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs. +The following jobs are available: +{available_jobs}""") assert len(jobs) == 1 + job = jobs[0] - if "ubuntu" not in job["os"]: + if not is_linux_job(job): raise Exception("Only Linux jobs can be executed locally") + return job + + +def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool): + DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker" + + job = find_linux_job(job_data, job_name=job_name, pr_jobs=pr_jobs) custom_env = {} - custom_env["DEPLOY"] = "1" + # Replicate src/ci/scripts/setup-environment.sh + # Adds custom environment variables to the job + if job_name.startswith("dist-"): + if job_name.endswith("-alt"): + custom_env["DEPLOY_ALT"] = "1" + else: + custom_env["DEPLOY"] = "1" custom_env.update({k: str(v) for (k, v) in job.get("env", {}).items()}) - args = [ - str(DOCKER_DIR / "run.sh"), - get_job_image(job) - ] + args = [str(DOCKER_DIR / "run.sh"), get_job_image(job)] env_formatted = [f"{k}={v}" for (k, v) in sorted(custom_env.items())] print(f"Executing `{' '.join(env_formatted)} {' '.join(args)}`") env = os.environ.copy() env.update(custom_env) - process = subprocess.Popen(args, env=env) - try: - process.wait() - except KeyboardInterrupt: - process.kill() + subprocess.run(args, env=env) -if __name__ == "__main__": - logging.basicConfig(level=logging.INFO) +def calculate_job_matrix(job_data: Dict[str, Any]): + github_ctx = get_github_ctx() - with open(JOBS_YAML_PATH) as f: - data = yaml.safe_load(f) + run_type = find_run_type(github_ctx) + logging.info(f"Job type: {run_type}") + with open(CI_DIR / "channel") as f: + channel = f.read().strip() + + jobs = [] + if run_type is not None: + jobs = calculate_jobs(run_type, job_data) + jobs = skip_jobs(jobs, channel) + + if not jobs: + raise Exception("Scheduled job list is empty, this is an error") + + run_type = format_run_type(run_type) + + logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") + print(f"jobs={json.dumps(jobs)}") + print(f"run_type={run_type}") + + +def create_cli_parser(): parser = argparse.ArgumentParser( - prog="ci.py", - description="Generate or run CI workflows" + prog="ci.py", description="Generate or run CI workflows" + ) + subparsers = parser.add_subparsers( + help="Command to execute", dest="command", required=True + ) + subparsers.add_parser( + "calculate-job-matrix", + help="Generate a matrix of jobs that should be executed in CI", + ) + run_parser = subparsers.add_parser( + "run-local", help="Run a CI jobs locally (on Linux)" ) - generate_matrix = argparse.ArgumentParser() - subparsers = parser.add_subparsers(help="Command to execute", dest="command", required=True) - subparsers.add_parser("calculate-job-matrix") - run_parser = subparsers.add_parser("run-local") run_parser.add_argument( "job_name", help="CI job that should be executed. By default, a merge (auto) " - "job with the given name will be executed" + "job with the given name will be executed", ) run_parser.add_argument( - "--pr", - action="store_true", - help="Run a PR job instead of an auto job" + "--pr", action="store_true", help="Run a PR job instead of an auto job" ) - args = parser.parse_args() - - if args.command == "calculate-job-matrix": - github_ctx = get_github_ctx() + return parser - run_type = find_run_type(github_ctx) - logging.info(f"Job type: {run_type}") - with open(CI_DIR / "channel") as f: - channel = f.read().strip() - - jobs = [] - if run_type is not None: - jobs = calculate_jobs(run_type, data) - jobs = skip_jobs(jobs, channel) +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) - if not jobs: - raise Exception("Scheduled job list is empty, this is an error") + with open(JOBS_YAML_PATH) as f: + data = yaml.safe_load(f) - run_type = format_run_type(run_type) + parser = create_cli_parser() + args = parser.parse_args() - logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") - print(f"jobs={json.dumps(jobs)}") - print(f"run_type={run_type}") + if args.command == "calculate-job-matrix": + calculate_job_matrix(data) elif args.command == "run-local": run_workflow_locally(data, args.job_name, args.pr) else: From 65819b193ae59cc1696eb796681df4f397900e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 7 Jan 2025 18:48:02 +0100 Subject: [PATCH 090/189] Update rustc-dev-guide --- src/doc/rustc-dev-guide/src/building/optimized-build.md | 2 +- src/doc/rustc-dev-guide/src/tests/ci.md | 7 +++---- src/doc/rustc-dev-guide/src/tests/docker.md | 9 +++++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index 3080dc6bf5d3f..8feda59829b45 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -126,4 +126,4 @@ Here is an example of how can `opt-dist` be used locally (outside of CI): [`Environment`]: https://github.com/rust-lang/rust/blob/ee451f8faccf3050c76cdcd82543c917b40c7962/src/tools/opt-dist/src/environment.rs#L5 > Note: if you want to run the actual CI pipeline, instead of running `opt-dist` locally, -> you can execute `DEPLOY=1 src/ci/docker/run.sh dist-x86_64-linux`. +> you can execute `python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux`. diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 5e27a2fd770c4..0ad1d2a28eded 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -28,7 +28,7 @@ Our CI is primarily executed on [GitHub Actions], with a single workflow defined in [`.github/workflows/ci.yml`], which contains a bunch of steps that are unified for all CI jobs that we execute. When a commit is pushed to a corresponding branch or a PR, the workflow executes the -[`calculate-job-matrix.py`] script, which dynamically generates the specific CI +[`ci.py`] script, which dynamically generates the specific CI jobs that should be executed. This script uses the [`jobs.yml`] file as an input, which contains a declarative configuration of all our CI jobs. @@ -299,8 +299,7 @@ platform’s custom [Docker container]. This has a lot of advantages for us: - We can avoid reinstalling tools (like QEMU or the Android emulator) every time thanks to Docker image caching. - Users can run the same tests in the same environment locally by just running - `src/ci/docker/run.sh image-name`, which is awesome to debug failures. Note - that there are only linux docker images available locally due to licensing and + `python3 src/ci/github-actions/ci.py run-local `, which is awesome to debug failures. Note that there are only linux docker images available locally due to licensing and other restrictions. The docker images prefixed with `dist-` are used for building artifacts while @@ -413,7 +412,7 @@ To learn more about the dashboard, see the [Datadog CI docs]. [GitHub Actions]: https://github.com/rust-lang/rust/actions [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml [`.github/workflows/ci.yml`]: https://github.com/rust-lang/rust/blob/master/.github/workflows/ci.yml -[`calculate-job-matrix.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/calculate-job-matrix.py +[`ci.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/ci.py [rust-lang-ci]: https://github.com/rust-lang-ci/rust/actions [bors]: https://github.com/bors [homu]: https://github.com/rust-lang/homu diff --git a/src/doc/rustc-dev-guide/src/tests/docker.md b/src/doc/rustc-dev-guide/src/tests/docker.md index 31e3825f5673e..a0aa8bd3e77b6 100644 --- a/src/doc/rustc-dev-guide/src/tests/docker.md +++ b/src/doc/rustc-dev-guide/src/tests/docker.md @@ -45,6 +45,15 @@ Some additional notes about using the Docker images: containers. With the container name, run `docker exec -it /bin/bash` where `` is the container name like `4ba195e95cef`. +The approach described above is a relatively low-level interface for running the Docker images +directly. If you want to run a full CI Linux job locally with Docker, in a way that is as close to CI as possible, you can use the following command: + +```bash +python3 src/ci/github-actions/ci.py run-local +# For example: +python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux-alt +``` + [Docker]: https://www.docker.com/ [`src/ci/docker`]: https://github.com/rust-lang/rust/tree/master/src/ci/docker [`src/ci/docker/run.sh`]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/run.sh From b9d6e9e73ffb2eaba9242d14ef40ee2ec61584a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 7 Jan 2025 21:36:37 +0100 Subject: [PATCH 091/189] warn about broken simd not only on structs but also enums and unions when we didn't opt in to it --- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- .../feature-gates/feature-gate-repr-simd.rs | 12 ++++- .../feature-gate-repr-simd.stderr | 44 +++++++++++++++++-- tests/ui/repr/issue-83505-repr-simd.rs | 2 + tests/ui/repr/issue-83505-repr-simd.stderr | 16 +++++-- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 3fbf121018615..c8500098add1a 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -242,7 +242,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Struct(..) => { + ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => { for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { diff --git a/tests/ui/feature-gates/feature-gate-repr-simd.rs b/tests/ui/feature-gates/feature-gate-repr-simd.rs index 65ade97c7e1c3..091dc479ef3d4 100644 --- a/tests/ui/feature-gates/feature-gate-repr-simd.rs +++ b/tests/ui/feature-gates/feature-gate-repr-simd.rs @@ -1,9 +1,17 @@ -#[repr(simd)] //~ error: SIMD types are experimental +#[repr(simd)] //~ ERROR: SIMD types are experimental struct Foo([u64; 2]); #[repr(C)] //~ ERROR conflicting representation hints //~^ WARN this was previously accepted -#[repr(simd)] //~ error: SIMD types are experimental +#[repr(simd)] //~ ERROR: SIMD types are experimental struct Bar([u64; 2]); +#[repr(simd)] //~ ERROR: SIMD types are experimental +//~^ ERROR: attribute should be applied to a struct +union U {f: u32} + +#[repr(simd)] //~ ERROR: SIMD types are experimental +//~^ error: attribute should be applied to a struct +enum E { X } + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-repr-simd.stderr b/tests/ui/feature-gates/feature-gate-repr-simd.stderr index 5a0ceb2dd74fb..3bf8ec6170597 100644 --- a/tests/ui/feature-gates/feature-gate-repr-simd.stderr +++ b/tests/ui/feature-gates/feature-gate-repr-simd.stderr @@ -18,6 +18,26 @@ LL | #[repr(simd)] = help: add `#![feature(repr_simd)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: SIMD types are experimental and possibly buggy + --> $DIR/feature-gate-repr-simd.rs:9:1 + | +LL | #[repr(simd)] + | ^^^^^^^^^^^^^ + | + = note: see issue #27731 for more information + = help: add `#![feature(repr_simd)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: SIMD types are experimental and possibly buggy + --> $DIR/feature-gate-repr-simd.rs:13:1 + | +LL | #[repr(simd)] + | ^^^^^^^^^^^^^ + | + = note: see issue #27731 for more information + = help: add `#![feature(repr_simd)]` 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[E0566]: conflicting representation hints --> $DIR/feature-gate-repr-simd.rs:4:8 | @@ -31,10 +51,28 @@ LL | #[repr(simd)] = note: for more information, see issue #68585 = note: `#[deny(conflicting_repr_hints)]` on by default -error: aborting due to 3 previous errors +error[E0517]: attribute should be applied to a struct + --> $DIR/feature-gate-repr-simd.rs:9:8 + | +LL | #[repr(simd)] + | ^^^^ +LL | +LL | union U {f: u32} + | ---------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/feature-gate-repr-simd.rs:13:8 + | +LL | #[repr(simd)] + | ^^^^ +LL | +LL | enum E { X } + | ------------ not a struct + +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0566, E0658. -For more information about an error, try `rustc --explain E0566`. +Some errors have detailed explanations: E0517, E0566, E0658. +For more information about an error, try `rustc --explain E0517`. Future incompatibility report: Future breakage diagnostic: error[E0566]: conflicting representation hints --> $DIR/feature-gate-repr-simd.rs:4:8 diff --git a/tests/ui/repr/issue-83505-repr-simd.rs b/tests/ui/repr/issue-83505-repr-simd.rs index 280b771d01539..bebbc636728fd 100644 --- a/tests/ui/repr/issue-83505-repr-simd.rs +++ b/tests/ui/repr/issue-83505-repr-simd.rs @@ -5,6 +5,8 @@ #[repr(simd)] //~^ ERROR: attribute should be applied to a struct [E0517] //~| ERROR: unsupported representation for zero-variant enum [E0084] +//~| ERROR: SIMD types are experimental and possibly buggy [E0658] + enum Es {} static CLs: Es; //~^ ERROR: free static item without body diff --git a/tests/ui/repr/issue-83505-repr-simd.stderr b/tests/ui/repr/issue-83505-repr-simd.stderr index df99baaf52293..44e154b4bb613 100644 --- a/tests/ui/repr/issue-83505-repr-simd.stderr +++ b/tests/ui/repr/issue-83505-repr-simd.stderr @@ -1,11 +1,21 @@ error: free static item without body - --> $DIR/issue-83505-repr-simd.rs:9:1 + --> $DIR/issue-83505-repr-simd.rs:11:1 | LL | static CLs: Es; | ^^^^^^^^^^^^^^- | | | help: provide a definition for the static: `= ;` +error[E0658]: SIMD types are experimental and possibly buggy + --> $DIR/issue-83505-repr-simd.rs:5:1 + | +LL | #[repr(simd)] + | ^^^^^^^^^^^^^ + | + = note: see issue #27731 for more information + = help: add `#![feature(repr_simd)]` 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[E0517]: attribute should be applied to a struct --> $DIR/issue-83505-repr-simd.rs:5:8 | @@ -24,7 +34,7 @@ LL | #[repr(simd)] LL | enum Es {} | ------- zero-variant enum -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0084, E0517. +Some errors have detailed explanations: E0084, E0517, E0658. For more information about an error, try `rustc --explain E0084`. From eadb76ec98c15166d298e0e92da6ee55a61a6b75 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 7 Jan 2025 22:46:18 +0100 Subject: [PATCH 092/189] Include rustc and rustdoc book in replace-version-placeholder --- src/tools/replace-version-placeholder/src/main.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs index 88118cab23589..fb2838a4ea03b 100644 --- a/src/tools/replace-version-placeholder/src/main.rs +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -10,7 +10,12 @@ fn main() { let version_str = t!(std::fs::read_to_string(&version_path), version_path); let version_str = version_str.trim(); walk::walk_many( - &[&root_path.join("compiler"), &root_path.join("library")], + &[ + &root_path.join("compiler"), + &root_path.join("library"), + &root_path.join("src/doc/rustc"), + &root_path.join("src/doc/rustdoc"), + ], |path, _is_dir| walk::filter_dirs(path), &mut |entry, contents| { if !contents.contains(VERSION_PLACEHOLDER) { From 5f04f98c9aaf04e5f670e04dc12d4665489859fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Jan 2025 22:06:58 +0000 Subject: [PATCH 093/189] Ensure that we don't try to access fields on a non-struct pattern type in diagnostic Fix #135209. --- .../rustc_resolve/src/late/diagnostics.rs | 4 ++- ...uct-pattern-on-non-struct-resolve-error.rs | 7 +++++ ...pattern-on-non-struct-resolve-error.stderr | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs create mode 100644 tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6ee02e9f47f15..3957a057fdbce 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1130,7 +1130,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let None = following_seg else { return }; for rib in self.ribs[ValueNS].iter().rev() { for (def_id, spans) in &rib.patterns_with_skipped_bindings { - if let Some(fields) = self.r.field_idents(*def_id) { + if let DefKind::Struct = self.r.tcx.def_kind(*def_id) + && let Some(fields) = self.r.field_idents(*def_id) + { for field in fields { if field.name == segment.ident.name { if spans.iter().all(|(_, had_error)| had_error.is_err()) { diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs new file mode 100644 index 0000000000000..c74c77fea60f4 --- /dev/null +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs @@ -0,0 +1,7 @@ +// Regression test for #135209. +// We ensure that we don't try to access fields on a non-struct pattern type. +fn main() { + if let Iterator::Item { .. } = 1 { //~ ERROR E0223 + x //~ ERROR E0425 + } +} diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr new file mode 100644 index 0000000000000..e31b19ab6bcbf --- /dev/null +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr @@ -0,0 +1,28 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:5:9 + | +LL | x + | ^ not found in this scope + +error[E0223]: ambiguous associated type + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 + | +LL | if let Iterator::Item { .. } = 1 { + | ^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | if let as Iterator>::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let ::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let ::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let as Iterator>::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + and 71 other candidates + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0223, E0425. +For more information about an error, try `rustc --explain E0223`. From d44f021904e3d5b2870e3c835cbad5e1421e83ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2025 00:10:16 +0000 Subject: [PATCH 094/189] Add check for missing fields in enum variant pattern --- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- ...ct-pattern-with-missing-fields-resolve-error.rs | 9 +++++++++ ...attern-with-missing-fields-resolve-error.stderr | 14 +++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3957a057fdbce..d15eca6927010 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1130,7 +1130,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let None = following_seg else { return }; for rib in self.ribs[ValueNS].iter().rev() { for (def_id, spans) in &rib.patterns_with_skipped_bindings { - if let DefKind::Struct = self.r.tcx.def_kind(*def_id) + if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id) && let Some(fields) = self.r.field_idents(*def_id) { for field in fields { diff --git a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs index 225891e390ff5..39f9f5a2c0208 100644 --- a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs +++ b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs @@ -3,6 +3,10 @@ struct Website { title: Option, } +enum Foo { + Bar { a: i32 }, +} + fn main() { let website = Website { url: "http://www.example.com".into(), @@ -18,4 +22,9 @@ fn main() { println!("[{}]({})", title, url); //~ ERROR cannot find value `title` in this scope //~^ NOTE not found in this scope } + + let x = Foo::Bar { a: 1 }; + if let Foo::Bar { .. } = x { //~ NOTE this pattern + println!("{a}"); //~ ERROR cannot find value `a` in this scope + } } diff --git a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr index 80fcd714400d6..b985b771754ee 100644 --- a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr +++ b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr @@ -1,5 +1,5 @@ error: expected `,` - --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:12:31 + --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:16:31 | LL | if let Website { url, Some(title) } = website { | ------- ^ @@ -7,13 +7,21 @@ LL | if let Website { url, Some(title) } = website { | while parsing the fields for this pattern error[E0425]: cannot find value `title` in this scope - --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:18:30 + --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:22:30 | LL | if let Website { url, .. } = website { | ------------------- this pattern doesn't include `title`, which is available in `Website` LL | println!("[{}]({})", title, url); | ^^^^^ not found in this scope -error: aborting due to 2 previous errors +error[E0425]: cannot find value `a` in this scope + --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:28:20 + | +LL | if let Foo::Bar { .. } = x { + | --------------- this pattern doesn't include `a`, which is available in `Bar` +LL | println!("{a}"); + | ^ help: a local variable with a similar name exists: `x` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. From 592f2c90da6a6e1b25b3b9c2f13a2e0cfb83dcfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2025 00:13:43 +0000 Subject: [PATCH 095/189] modify test to side-step platform-dependent stderr output --- ...uct-pattern-on-non-struct-resolve-error.rs | 5 ++- ...pattern-on-non-struct-resolve-error.stderr | 40 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs index c74c77fea60f4..17a5bad0e6c0f 100644 --- a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs @@ -1,7 +1,10 @@ // Regression test for #135209. // We ensure that we don't try to access fields on a non-struct pattern type. fn main() { - if let Iterator::Item { .. } = 1 { //~ ERROR E0223 + if let as Iterator>::Item { .. } = 1 { + //~^ ERROR E0658 + //~| ERROR E0071 + //~| ERROR E0277 x //~ ERROR E0425 } } diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr index e31b19ab6bcbf..793c2d1e97fc0 100644 --- a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr @@ -1,28 +1,34 @@ error[E0425]: cannot find value `x` in this scope - --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:5:9 + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:8:9 | LL | x | ^ not found in this scope -error[E0223]: ambiguous associated type +error[E0658]: usage of qualified paths in this context is experimental --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 | -LL | if let Iterator::Item { .. } = 1 { - | ^^^^^^^^^^^^^^ +LL | if let as Iterator>::Item { .. } = 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use fully-qualified syntax + = note: see issue #86935 for more information + = help: add `#![feature(more_qualified_paths)]` 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[E0071]: expected struct, variant or union type, found inferred type + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 + | +LL | if let as Iterator>::Item { .. } = 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a struct + +error[E0277]: `Vec<()>` is not an iterator + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 + | +LL | if let as Iterator>::Item { .. } = 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Vec<()>` is not an iterator | -LL | if let as Iterator>::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | if let ::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~ -LL | if let ::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | if let as Iterator>::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - and 71 other candidates + = help: the trait `Iterator` is not implemented for `Vec<()>` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0223, E0425. -For more information about an error, try `rustc --explain E0223`. +Some errors have detailed explanations: E0071, E0277, E0425, E0658. +For more information about an error, try `rustc --explain E0071`. From ceabc95dd12c832b1f24bb5e39ec6576422a7b4d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 8 Jan 2025 13:33:51 +1100 Subject: [PATCH 096/189] Add more comments to some of the test steps --- src/bootstrap/src/core/build_steps/test.rs | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index dc6dbbac9d25a..914260e38d1d9 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -31,6 +31,7 @@ use crate::{CLang, DocTests, GitRepo, Mode, PathSet, envify}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; +/// Runs `cargo test` on various internal tools used by bootstrap. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateBootstrap { path: PathBuf, @@ -43,13 +44,21 @@ impl Step for CrateBootstrap { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + // This step is responsible for several different tool paths. By default + // it will test all of them, but requesting specific tools on the + // command-line (e.g. `./x test suggest-tests`) will test only the + // specified tools. run.path("src/tools/jsondoclint") .path("src/tools/suggest-tests") .path("src/tools/replace-version-placeholder") + // We want `./x test tidy` to _run_ the tidy tool, not its tests. + // So we need a separate alias to test the tidy tool itself. .alias("tidyselftest") } fn make_run(run: RunConfig<'_>) { + // Create and ensure a separate instance of this step for each path + // that was selected on the command-line (or selected by default). for path in run.paths { let path = path.assert_single_path().path.clone(); run.builder.ensure(CrateBootstrap { host: run.target, path }); @@ -60,6 +69,8 @@ impl Step for CrateBootstrap { let bootstrap_host = builder.config.build; let compiler = builder.compiler(0, bootstrap_host); let mut path = self.path.to_str().unwrap(); + + // Map alias `tidyselftest` back to the actual crate path of tidy. if path == "tidyselftest" { path = "src/tools/tidy"; } @@ -212,6 +223,9 @@ impl Step for HtmlCheck { } } +/// Builds cargo and then runs the `src/tools/cargotest` tool, which checks out +/// some representative crate repositories and runs `cargo test` on them, in +/// order to test cargo. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Cargotest { stage: u32, @@ -257,6 +271,7 @@ impl Step for Cargotest { } } +/// Runs `cargo test` for cargo itself. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Cargo { stage: u32, @@ -385,6 +400,7 @@ impl Step for RustAnalyzer { } } +/// Runs `cargo test` for rustfmt. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Rustfmt { stage: u32, @@ -589,6 +605,8 @@ impl Step for Miri { } } +/// Runs `cargo miri test` to demonstrate that `src/tools/miri/cargo-miri` +/// works and that libtest works under miri. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CargoMiri { target: TargetSelection, @@ -1020,6 +1038,10 @@ impl Step for RustdocGUI { } } +/// Runs `src/tools/tidy` and `cargo fmt --check` to detect various style +/// problems in the repository. +/// +/// (To run the tidy tool's internal tests, use the alias "tidyselftest" instead.) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Tidy; @@ -1230,6 +1252,8 @@ impl Step for RunMakeSupport { } } +/// Runs `cargo test` on the `src/tools/run-make-support` crate. +/// That crate is used by run-make tests. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateRunMakeSupport { host: TargetSelection, @@ -2466,6 +2490,10 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> } } +/// Runs `cargo test` for the compiler crates in `compiler/`. +/// +/// (This step does not test `rustc_codegen_cranelift` or `rustc_codegen_gcc`, +/// which have their own separate test steps.) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateLibrustc { compiler: Compiler, @@ -2494,6 +2522,7 @@ impl Step for CrateLibrustc { fn run(self, builder: &Builder<'_>) { builder.ensure(compile::Std::new(self.compiler, self.target)); + // To actually run the tests, delegate to a copy of the `Crate` step. builder.ensure(Crate { compiler: self.compiler, target: self.target, @@ -2619,6 +2648,13 @@ fn prepare_cargo_test( cargo } +/// Runs `cargo test` for standard library crates. +/// +/// (Also used internally to run `cargo test` for compiler crates.) +/// +/// FIXME(Zalathar): Try to split this into two separate steps: a user-visible +/// step for testing standard library crates, and an internal step used for both +/// library crates and compiler crates. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Crate { pub compiler: Compiler, @@ -3552,6 +3588,10 @@ impl Step for CodegenGCC { } } +/// Test step that does two things: +/// - Runs `cargo test` for the `src/etc/test-float-parse` tool. +/// - Invokes the `test-float-parse` tool to test the standard library's +/// float parsing routines. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TestFloatParse { path: PathBuf, @@ -3625,6 +3665,9 @@ impl Step for TestFloatParse { } } +/// Runs the tool `src/tools/collect-license-metadata` in `ONLY_CHECK=1` mode, +/// which verifies that `license-metadata.json` is up-to-date and therefore +/// running the tool normally would not update anything. #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct CollectLicenseMetadata; From 8461d3febdcfc0808ef0620c3d8f4636fc138a69 Mon Sep 17 00:00:00 2001 From: A_A <21040751+Otto-AA@users.noreply.github.com> Date: Wed, 8 Jan 2025 07:51:56 +0100 Subject: [PATCH 097/189] Remove unnecessary string allocation --- clippy_lints/src/manual_is_ascii_check.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 091203184b6fb..ba69b1aaf5b6d 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; @@ -123,15 +123,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { extract_msrv_attr!(LateContext); } -fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>) -> Option<(Span, String)> { +fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> { let local_hid = path_to_local(arg)?; if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid) // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given && ty_span == span { let arg_type = cx.typeck_results().expr_ty(arg); - let ty_str = arg_type.to_string(); - return Some((*ty_span, ty_str)); + return Some((*ty_span, arg_type)); } None } @@ -141,7 +140,7 @@ fn check_is_ascii( span: Span, recv: &Expr<'_>, range: &CharRange, - ty_sugg: Option<(Span, String)>, + ty_sugg: Option<(Span, Ty<'_>)>, ) { let sugg = match range { CharRange::UpperChar => "is_ascii_uppercase", @@ -155,8 +154,8 @@ fn check_is_ascii( let mut app = Applicability::MachineApplicable; let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))]; - if let Some((ty_span, ty_str)) = ty_sugg { - suggestion.push((ty_span, format!("{recv}: {ty_str}"))); + if let Some((ty_span, ty)) = ty_sugg { + suggestion.push((ty_span, format!("{recv}: {ty}"))); } span_lint_and_then( From 9942b77c5b0a2190453d5e71fe54c6c980fd3f79 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 11 Dec 2024 20:23:52 +0000 Subject: [PATCH 098/189] Avoid passing a full Expr when only the Span is used --- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/confirm.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 8c8a8d6d9228a..52b5b031a0af3 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -837,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. let args = self.typeck_results.borrow().node_args(expr.hir_id); - self.add_wf_bounds(args, expr); + self.add_wf_bounds(args, expr.span); ty } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2f6e50c80149e..4af0c9ea000a1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -577,11 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Registers obligations that all `args` are well-formed. - pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &hir::Expr<'_>) { + pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, span: Span) { for arg in args.iter().filter(|arg| { matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) }) { - self.register_wf_obligation(arg, expr.span, ObligationCauseCode::WellFormed(None)); + self.register_wf_obligation(arg, span, ObligationCauseCode::WellFormed(None)); } } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 0c93c9817b467..f549ced9dc332 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -611,7 +611,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // this is a projection from a trait reference, so we have to // make sure that the trait reference inputs are well-formed. - self.add_wf_bounds(all_args, self.call_expr); + self.add_wf_bounds(all_args, self.call_expr.span); // the function type must also be well-formed (this is not // implied by the args being well-formed because of inherent From 5df69191cb89dd5e5a23d01d0d69d0d507f45a77 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 11 Dec 2024 20:39:50 +0000 Subject: [PATCH 099/189] Avoid passing a full Pat when only the Span/HirId is used --- compiler/rustc_hir_typeck/src/pat.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 4870e6193c3f1..15acb9d143ac2 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -279,7 +279,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) } PatKind::Path(ref qpath) => { - self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) + self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti) } PatKind::Struct(ref qpath, fields, has_rest_pat) => { self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) @@ -1053,7 +1053,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_path( &self, - pat: &Pat<'tcx>, + hir_id: HirId, + span: Span, qpath: &hir::QPath<'_>, path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), expected: Ty<'tcx>, @@ -1072,8 +1073,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { let expected = "unit struct, unit variant or constant"; - let e = - report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected); + let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected); return Ty::new_error(tcx, e); } Res::SelfCtor(def_id) => { @@ -1088,7 +1088,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { res, None, qpath, - pat.span, + span, E0533, "unit struct", ); @@ -1107,11 +1107,11 @@ 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); + self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id); if let Err(err) = - self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) + self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty) { - self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments); + self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments); } pat_ty } @@ -1154,13 +1154,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn emit_bad_pat_path( &self, mut e: Diag<'_>, - pat: &hir::Pat<'tcx>, + hir_id: HirId, + pat_span: Span, res: Res, pat_res: Res, pat_ty: Ty<'tcx>, segments: &'tcx [hir::PathSegment<'tcx>], ) { - let pat_span = pat.span; if let Some(span) = self.tcx.hir().res_span(pat_res) { e.span_label(span, format!("{} defined here", res.descr())); if let [hir::PathSegment { ident, .. }] = &*segments { @@ -1173,7 +1173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { res.descr(), ), ); - match self.tcx.parent_hir_node(pat.hir_id) { + match self.tcx.parent_hir_node(hir_id) { hir::Node::PatField(..) => { e.span_suggestion_verbose( ident.span.shrink_to_hi(), From c9365dd09f30ff2df8fd335e80b82202ba9f8a85 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 11 Dec 2024 16:50:45 +0000 Subject: [PATCH 100/189] Exhaustively handle expressions in patterns --- compiler/rustc_ast_lowering/src/expr.rs | 51 ++++++++-------- compiler/rustc_ast_lowering/src/index.rs | 8 +++ compiler/rustc_ast_lowering/src/lib.rs | 1 + compiler/rustc_ast_lowering/src/pat.rs | 59 +++++++++++++++---- compiler/rustc_hir/src/hir.rs | 29 ++++++++- compiler/rustc_hir/src/intravisit.rs | 18 +++++- .../src/hir_ty_lowering/mod.rs | 42 +++++++------ compiler/rustc_hir_pretty/src/lib.rs | 20 ++++++- compiler/rustc_hir_typeck/src/expr.rs | 3 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 9 +++ .../rustc_hir_typeck/src/method/suggest.rs | 5 ++ compiler/rustc_hir_typeck/src/pat.rs | 44 ++++++++++---- compiler/rustc_hir_typeck/src/upvar.rs | 9 +-- compiler/rustc_hir_typeck/src/writeback.rs | 22 +++++-- compiler/rustc_middle/src/hir/map/mod.rs | 2 + .../rustc_mir_build/src/thir/pattern/mod.rs | 37 ++++-------- .../src/default_numeric_fallback.rs | 23 +++++++- src/tools/clippy/clippy_lints/src/len_zero.rs | 12 +++- .../clippy_lints/src/manual_is_ascii_check.rs | 37 ++++++++---- .../clippy_lints/src/manual_range_patterns.rs | 13 ++-- .../clippy_lints/src/matches/match_bool.rs | 4 +- .../src/matches/match_same_arms.rs | 8 +-- .../src/matches/match_str_case_mismatch.rs | 6 +- .../src/matches/needless_match.rs | 12 ++-- .../src/matches/overlapping_arms.rs | 8 ++- .../src/matches/redundant_pattern_match.rs | 4 +- .../clippy_lints/src/matches/single_match.rs | 6 +- .../clippy_lints/src/string_patterns.rs | 4 +- .../clippy/clippy_lints/src/utils/author.rs | 29 +++++++-- src/tools/clippy/clippy_utils/src/consts.rs | 59 ++++++++++++------- .../clippy/clippy_utils/src/hir_utils.rs | 46 ++++++++++++--- src/tools/clippy/tests/ui/author/if.stdout | 2 +- src/tools/clippy/tests/ui/author/loop.stdout | 2 +- .../clippy/tests/ui/author/matches.stdout | 4 +- .../clippy/tests/ui/author/struct.stdout | 4 +- tests/ui/unpretty/unpretty-expr-fn-arg.stdout | 2 +- 36 files changed, 447 insertions(+), 197 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d16a3ce390dbe..a76ca6772e52e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), - ExprKind::ConstBlock(c) => { - let c = self.with_new_scopes(c.value.span, |this| { - let def_id = this.local_def_id(c.id); - hir::ConstBlock { - def_id, - hir_id: this.lower_node_id(c.id), - body: this.lower_const_body(c.value.span, Some(&c.value)), - } - }); - hir::ExprKind::ConstBlock(c) - } + ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::Repeat(expr, count) => { let expr = self.lower_expr(expr); let count = self.lower_array_length_to_const_arg(count); @@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ohs = self.lower_expr(ohs); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(token_lit) => { - let lit_kind = match LitKind::from_token_lit(*token_lit) { - Ok(lit_kind) => lit_kind, - Err(err) => { - let guar = - report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span); - LitKind::Err(guar) - } - }; - let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind)); - hir::ExprKind::Lit(lit) - } + ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), ExprKind::IncludedBytes(bytes) => { let lit = self.arena.alloc(respan( self.lower_span(e.span), @@ -403,6 +382,32 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } + pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock { + self.with_new_scopes(c.value.span, |this| { + let def_id = this.local_def_id(c.id); + hir::ConstBlock { + def_id, + hir_id: this.lower_node_id(c.id), + body: this.lower_const_body(c.value.span, Some(&c.value)), + } + }) + } + + pub(crate) fn lower_lit( + &mut self, + token_lit: &token::Lit, + span: Span, + ) -> &'hir Spanned { + let lit_kind = match LitKind::from_token_lit(*token_lit) { + Ok(lit_kind) => lit_kind, + Err(err) => { + let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span); + LitKind::Err(guar) + } + }; + self.arena.alloc(respan(self.lower_span(span), lit_kind)) + } + fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { match u { UnOp::Deref => hir::UnOp::Deref, diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index c3ff7b4b89722..29d4fb9ef2597 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -209,6 +209,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_pat_expr(&mut self, expr: &'hir PatExpr<'hir>) { + self.insert(expr.span, expr.hir_id, Node::PatExpr(expr)); + + self.with_parent(expr.hir_id, |this| { + intravisit::walk_pat_expr(this, expr); + }); + } + fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { self.insert(field.span, field.hir_id, Node::PatField(field)); self.with_parent(field.hir_id, |this| { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index fe2d5a594f312..0e28590bd6609 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -35,6 +35,7 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(rustdoc_internals)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 40e7d6430fde5..27b8bdefb0554 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_span::source_map::Spanned; +use rustc_middle::span_bug; +use rustc_span::source_map::{Spanned, respan}; use rustc_span::{Ident, Span}; use super::errors::{ @@ -367,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // } // m!(S); // ``` - fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> { - match &expr.kind { - ExprKind::Lit(..) - | ExprKind::ConstBlock(..) - | ExprKind::IncludedBytes(..) - | ExprKind::Err(_) - | ExprKind::Dummy => {} - ExprKind::Path(..) if allow_paths => {} - ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} + fn lower_expr_within_pat( + &mut self, + expr: &Expr, + allow_paths: bool, + ) -> &'hir hir::PatExpr<'hir> { + let err = |guar| hir::PatExprKind::Lit { + lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))), + negated: false, + }; + let kind = match &expr.kind { + ExprKind::Lit(lit) => { + hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false } + } + ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), + ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { + lit: self.arena.alloc(respan( + self.lower_span(expr.span), + LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked), + )), + negated: false, + }, + ExprKind::Err(guar) => err(*guar), + ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"), + ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + )), + ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => { + hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true } + } _ => { let pattern_from_macro = expr.is_approximately_pattern(); let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { span: expr.span, pattern_from_macro_note: pattern_from_macro, }); - return self.arena.alloc(self.expr_err(expr.span, guar)); + err(guar) } - } - self.lower_expr(expr) + }; + self.arena.alloc(hir::PatExpr { + hir_id: self.lower_node_id(expr.id), + span: expr.span, + kind, + }) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2e4b6748731aa..4d452d6cb3732 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1519,6 +1519,26 @@ impl fmt::Debug for DotDotPos { } } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct PatExpr<'hir> { + pub hir_id: HirId, + pub span: Span, + pub kind: PatExprKind<'hir>, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum PatExprKind<'hir> { + Lit { + lit: &'hir Lit, + // FIXME: move this into `Lit` and handle negated literal expressions + // once instead of matching on unop neg expressions everywhere. + negated: bool, + }, + ConstBlock(ConstBlock), + /// A path pattern for a unit struct/variant or a (maybe-associated) constant. + Path(QPath<'hir>), +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum PatKind<'hir> { /// Represents a wildcard pattern (i.e., `_`). @@ -1564,13 +1584,13 @@ pub enum PatKind<'hir> { Ref(&'hir Pat<'hir>, Mutability), /// A literal. - Lit(&'hir Expr<'hir>), + Lit(&'hir PatExpr<'hir>), /// A guard pattern (e.g., `x if guard(x)`). Guard(&'hir Pat<'hir>, &'hir Expr<'hir>), /// A range pattern (e.g., `1..=2` or `1..2`). - Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd), + Range(Option<&'hir PatExpr<'hir>>, Option<&'hir PatExpr<'hir>>, RangeEnd), /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`. /// @@ -4144,6 +4164,10 @@ pub enum Node<'hir> { OpaqueTy(&'hir OpaqueTy<'hir>), Pat(&'hir Pat<'hir>), PatField(&'hir PatField<'hir>), + /// Needed as its own node with its own HirId for tracking + /// the unadjusted type of literals within patterns + /// (e.g. byte str literals not being of slice type). + PatExpr(&'hir PatExpr<'hir>), Arm(&'hir Arm<'hir>), Block(&'hir Block<'hir>), LetStmt(&'hir LetStmt<'hir>), @@ -4200,6 +4224,7 @@ impl<'hir> Node<'hir> { | Node::Block(..) | Node::Ctor(..) | Node::Pat(..) + | Node::PatExpr(..) | Node::Arm(..) | Node::LetStmt(..) | Node::Crate(..) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index f0480afd139f4..b832843aa6e2f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -342,6 +342,9 @@ pub trait Visitor<'v>: Sized { fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result { walk_pat_field(self, f) } + fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result { + walk_pat_expr(self, expr) + } fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { walk_anon_const(self, c) } @@ -685,10 +688,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } - PatKind::Lit(ref expression) => try_visit!(visitor.visit_expr(expression)), + PatKind::Lit(ref expression) => try_visit!(visitor.visit_pat_expr(expression)), PatKind::Range(ref lower_bound, ref upper_bound, _) => { - visit_opt!(visitor, visit_expr, lower_bound); - visit_opt!(visitor, visit_expr, upper_bound); + visit_opt!(visitor, visit_pat_expr, lower_bound); + visit_opt!(visitor, visit_pat_expr, upper_bound); } PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { @@ -710,6 +713,15 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<' visitor.visit_pat(field.pat) } +pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result { + try_visit!(visitor.visit_id(expr.hir_id)); + match &expr.kind { + PatExprKind::Lit { .. } => V::Result::output(), + PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), + PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span), + } +} + pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result { try_visit!(visitor.visit_id(constant.hir_id)); visitor.visit_nested_body(constant.body) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2154568c51267..0a41dad0dd837 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2449,17 +2449,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_error(tcx, err) } hir::PatKind::Range(start, end, include_end) => { - let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> { - let (expr, neg) = match expr.kind { - hir::ExprKind::Unary(hir::UnOp::Neg, negated) => { - (negated, Some((expr.hir_id, expr.span))) - } - _ => (expr, None), - }; - let (c, c_ty) = match &expr.kind { - hir::ExprKind::Lit(lit) => { + let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> { + let (c, c_ty) = match expr.kind { + hir::PatExprKind::Lit { lit, negated } => { let lit_input = - LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; + LitToConstInput { lit: &lit.node, ty, neg: negated }; let ct = match tcx.lit_to_const(lit_input) { Ok(c) => c, Err(LitToConstError::Reported(err)) => { @@ -2470,23 +2464,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { (ct, ty) } - hir::ExprKind::Path(hir::QPath::Resolved( + hir::PatExprKind::Path(hir::QPath::Resolved( _, path @ &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, )) => { - let _ = self.prohibit_generic_args( + match self.prohibit_generic_args( path.segments.iter(), GenericsArgsErrExtend::Param(def_id), - ); - let ty = tcx - .type_of(def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - let ct = self.lower_const_param(def_id, expr.hir_id); - (ct, ty) + ) { + Ok(()) => { + let ty = tcx + .type_of(def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"); + let ct = self.lower_const_param(def_id, expr.hir_id); + (ct, ty) + } + Err(guar) => ( + ty::Const::new_error(tcx, guar), + Ty::new_error(tcx, guar), + ), + } } _ => { @@ -2497,9 +2498,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } }; self.record_ty(expr.hir_id, c_ty, expr.span); - if let Some((id, span)) = neg { - self.record_ty(id, c_ty, span); - } c }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 16bb0dd328cdc..632a12b2c3fd4 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -199,6 +199,7 @@ impl<'a> State<'a> { Node::OpaqueTy(o) => self.print_opaque_ty(o), Node::Pat(a) => self.print_pat(a), Node::PatField(a) => self.print_patfield(a), + Node::PatExpr(a) => self.print_pat_expr(a), Node::Arm(a) => self.print_arm(a), Node::Infer(_) => self.word("_"), Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident), @@ -1849,6 +1850,19 @@ impl<'a> State<'a> { } } + fn print_pat_expr(&mut self, expr: &hir::PatExpr<'_>) { + match &expr.kind { + hir::PatExprKind::Lit { lit, negated } => { + if *negated { + self.word("-"); + } + self.print_literal(lit); + } + hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c), + hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true), + } + } + fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); @@ -1966,17 +1980,17 @@ impl<'a> State<'a> { self.pclose(); } } - PatKind::Lit(e) => self.print_expr(e), + PatKind::Lit(e) => self.print_pat_expr(e), PatKind::Range(begin, end, end_kind) => { if let Some(expr) = begin { - self.print_expr(expr); + self.print_pat_expr(expr); } match end_kind { RangeEnd::Included => self.word("..."), RangeEnd::Excluded => self.word(".."), } if let Some(expr) = end { - self.print_expr(expr); + self.print_pat_expr(expr); } } PatKind::Slice(before, slice, after) => { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 52b5b031a0af3..ca4be850a8edd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -430,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::Node::AssocItemConstraint(_) | hir::Node::TraitRef(_) | hir::Node::PatField(_) + | hir::Node::PatExpr(_) | hir::Node::LetStmt(_) | hir::Node::Synthetic | hir::Node::Err(_) @@ -1796,7 +1797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_const_block( + pub(super) fn check_expr_const_block( &self, block: &'tcx hir::ConstBlock, expected: Expectation<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 4af0c9ea000a1..4130f0c11dd78 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1039,6 +1039,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_id, span, ), + Res::Err => { + return ( + Ty::new_error( + tcx, + tcx.dcx().span_delayed_bug(span, "could not resolve path {:?}"), + ), + res, + ); + } _ => bug!("instantiate_value_path on {:?}", res), }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b4f1dcfb9cc8a..72a1e4af9bfce 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -170,6 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, .. }) + | hir::Node::PatExpr(&hir::PatExpr { + kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)), + span, + .. + }) | hir::Node::Pat(&hir::Pat { kind: hir::PatKind::Path(QPath::TypeRelative(rcvr, segment)) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 15acb9d143ac2..c8a04c331a2cc 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -30,6 +30,7 @@ use tracing::{debug, instrument, trace}; use ty::VariantDef; use super::report_unexpected_variant_res; +use crate::expectation::Expectation; use crate::gather_locals::DeclOrigin; use crate::{FnCtxt, LoweredTy, errors}; @@ -398,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // // Call `resolve_vars_if_possible` here for inline const blocks. - PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { + PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() { ty::Ref(..) => AdjustMode::Pass, _ => AdjustMode::Peel, }, @@ -493,10 +494,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (expected, def_br, max_ref_mutbl) } + fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> { + let ty = match <.kind { + rustc_hir::PatExprKind::Lit { lit, .. } => { + self.check_expr_lit(lit, Expectation::NoExpectation) + } + rustc_hir::PatExprKind::ConstBlock(c) => { + self.check_expr_const_block(c, Expectation::NoExpectation) + } + rustc_hir::PatExprKind::Path(qpath) => { + let (res, opt_ty, segments) = + self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span); + self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0 + } + }; + self.write_ty(lt.hir_id, ty); + ty + } + fn check_pat_lit( &self, span: Span, - lt: &hir::Expr<'tcx>, + lt: &hir::PatExpr<'tcx>, expected: Ty<'tcx>, ti: &TopInfo<'tcx>, ) -> Ty<'tcx> { @@ -507,7 +526,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Byte string patterns behave the same way as array patterns // They can denote both statically and dynamically-sized byte arrays. let mut pat_ty = ty; - if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind { + if let hir::PatExprKind::Lit { + lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, .. + } = lt.kind + { let expected = self.structurally_resolve_type(span, expected); if let ty::Ref(_, inner_ty, _) = *expected.kind() && self.try_structurally_resolve_type(span, inner_ty).is_slice() @@ -524,7 +546,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if self.tcx.features().string_deref_patterns() - && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind + && let hir::PatExprKind::Lit { + lit: Spanned { node: ast::LitKind::Str(..), .. }, .. + } = lt.kind { let tcx = self.tcx; let expected = self.resolve_vars_if_possible(expected); @@ -565,15 +589,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_range( &self, span: Span, - lhs: Option<&'tcx hir::Expr<'tcx>>, - rhs: Option<&'tcx hir::Expr<'tcx>>, + lhs: Option<&'tcx hir::PatExpr<'tcx>>, + rhs: Option<&'tcx hir::PatExpr<'tcx>>, expected: Ty<'tcx>, ti: &TopInfo<'tcx>, ) -> Ty<'tcx> { - let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { + let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr { None => None, Some(expr) => { - let ty = self.check_expr(expr); + let ty = self.check_pat_expr_unadjusted(expr); // Check that the end-point is possibly of numeric or char type. // The early check here is not for correctness, but rather better // diagnostics (e.g. when `&str` is being matched, `expected` will @@ -1813,9 +1837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else if inexistent_fields.len() == 1 { match pat_field.pat.kind { - PatKind::Lit(expr) + PatKind::Lit(_) if !self.may_coerce( - self.typeck_results.borrow().expr_ty(expr), + self.typeck_results.borrow().node_type(pat_field.pat.hir_id), self.field_ty(field.span, field_def, args), ) => {} _ => { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 53993ba8d6ca4..cac891c4e4c4f 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -147,15 +147,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { self.visit_body(body); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); } - hir::ExprKind::ConstBlock(anon_const) => { - let body = self.fcx.tcx.hir().body(anon_const.body); - self.visit_body(body); - } _ => {} } intravisit::walk_expr(self, expr); } + + fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { + let body = self.fcx.tcx.hir().body(c.body); + self.visit_body(body); + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 5612aa75aae44..f63a0b17964f7 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -246,6 +246,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } } + + fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) { + self.visit_node_id(span, anon_const.hir_id); + + let body = self.tcx().hir().body(anon_const.body); + self.visit_body(body); + } } /////////////////////////////////////////////////////////////////////////// @@ -275,11 +282,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { self.visit_field_id(e.hir_id); } - hir::ExprKind::ConstBlock(anon_const) => { - self.visit_node_id(e.span, anon_const.hir_id); - - let body = self.tcx().hir().body(anon_const.body); - self.visit_body(body); + hir::ExprKind::ConstBlock(ref anon_const) => { + self.visit_const_block(e.span, anon_const); } _ => {} } @@ -335,6 +339,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { intravisit::walk_pat(self, p); } + fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) { + self.visit_node_id(expr.span, expr.hir_id); + if let hir::PatExprKind::ConstBlock(c) = &expr.kind { + self.visit_const_block(expr.span, c); + } + intravisit::walk_pat_expr(self, expr); + } + fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) { intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.hir_id); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index dee4c424387f6..632935eefeb66 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -938,6 +938,7 @@ impl<'hir> Map<'hir> { Node::OpaqueTy(op) => op.span, Node::Pat(pat) => pat.span, Node::PatField(field) => field.span, + Node::PatExpr(lit) => lit.span, Node::Arm(arm) => arm.span, Node::Block(block) => block.span, Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)), @@ -1209,6 +1210,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Node::OpaqueTy(_) => node_str("opaque type"), Node::Pat(_) => node_str("pat"), Node::PatField(_) => node_str("pattern field"), + Node::PatExpr(_) => node_str("pattern literal"), Node::Param(_) => node_str("param"), Node::Arm(_) => node_str("arm"), Node::Block(_) => node_str("block"), diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 54510faf2e182..305019bc9fcb5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -154,7 +154,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range_endpoint( &mut self, - expr: Option<&'tcx hir::Expr<'tcx>>, + expr: Option<&'tcx hir::PatExpr<'tcx>>, ) -> Result< (Option>, Option>, Option), ErrorGuaranteed, @@ -200,13 +200,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// This is only called when the range is already known to be malformed. fn error_on_literal_overflow( &self, - expr: Option<&'tcx hir::Expr<'tcx>>, + expr: Option<&'tcx hir::PatExpr<'tcx>>, ty: Ty<'tcx>, ) -> Result<(), ErrorGuaranteed> { - use hir::{ExprKind, UnOp}; use rustc_ast::ast::LitKind; - let Some(mut expr) = expr else { + let Some(expr) = expr else { return Ok(()); }; let span = expr.span; @@ -214,12 +213,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // We need to inspect the original expression, because if we only inspect the output of // `eval_bits`, an overflowed value has already been wrapped around. // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. - let mut negated = false; - if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind { - negated = true; - expr = sub_expr; - } - let ExprKind::Lit(lit) = expr.kind else { + let hir::PatExprKind::Lit { lit, negated } = expr.kind else { return Ok(()); }; let LitKind::Int(lit_val, _) = lit.node else { @@ -248,8 +242,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range( &mut self, - lo_expr: Option<&'tcx hir::Expr<'tcx>>, - hi_expr: Option<&'tcx hir::Expr<'tcx>>, + lo_expr: Option<&'tcx hir::PatExpr<'tcx>>, + hi_expr: Option<&'tcx hir::PatExpr<'tcx>>, end: RangeEnd, ty: Ty<'tcx>, span: Span, @@ -662,25 +656,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// The special case for negation exists to allow things like `-128_i8` /// which would overflow if we tried to evaluate `128_i8` and then negate /// afterwards. - fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { - let (lit, neg) = match expr.kind { - hir::ExprKind::Path(ref qpath) => { + fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> { + let (lit, neg) = match &expr.kind { + hir::PatExprKind::Path(qpath) => { return self.lower_path(qpath, expr.hir_id, expr.span).kind; } - hir::ExprKind::ConstBlock(ref anon_const) => { + hir::PatExprKind::ConstBlock(anon_const) => { return self.lower_inline_const(anon_const, expr.hir_id, expr.span); } - hir::ExprKind::Lit(ref lit) => (lit, false), - hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { - let hir::ExprKind::Lit(ref lit) = expr.kind else { - span_bug!(expr.span, "not a literal: {:?}", expr); - }; - (lit, true) - } - _ => span_bug!(expr.span, "not a literal: {:?}", expr), + hir::PatExprKind::Lit { lit, negated } => (lit, *negated), }; - let ct_ty = self.typeck_results.expr_ty(expr); + let ct_ty = self.typeck_results.node_type(expr.hir_id); let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind, diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 3b3a78cb11530..f579c9a41828c 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -3,8 +3,11 @@ use clippy_utils::numeric_literal; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; -use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt}; +use rustc_hir::{ + Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Pat, PatExpr, PatExprKind, PatKind, Stmt, StmtKind, + StructTailExpr, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { walk_expr(self, expr); } + fn visit_pat(&mut self, pat: &'tcx Pat<'_>) { + match pat.kind { + PatKind::Lit(&PatExpr { + hir_id, + kind: PatExprKind::Lit { lit, .. }, + .. + }) => { + let ty = self.cx.typeck_results().node_type(hir_id); + self.check_lit(lit, ty, hir_id); + return; + }, + _ => {}, + } + walk_pat(self, pat) + } + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { match stmt.kind { // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric` diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 3ea758e176f0b..d6c1cb5e6e439 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -8,8 +8,8 @@ use rustc_hir::def::Res; 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, + ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy, + QPath, TraitItemRef, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; @@ -163,7 +163,13 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let ExprKind::Let(lt) = expr.kind && match lt.pat.kind { PatKind::Slice([], None, []) => true, - PatKind::Lit(lit) if is_empty_string(lit) => true, + PatKind::Lit(lit) => match lit.kind { + PatExprKind::Lit { lit, .. } => match lit.node { + LitKind::Str(lit, _) => lit.as_str().is_empty(), + _ => false, + }, + _ => false, + }, _ => false, } && !expr.span.from_expansion() diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 3f01f3cf30aea..5b9eedd9b8bf1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -7,7 +7,7 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; +use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { { let arg = peel_ref_operators(cx, arg); let ty_sugg = get_ty_sugg(cx, arg, start); - let range = check_range(start, end); + let range = check_expr_range(start, end); check_is_ascii(cx, expr.span, arg, &range, ty_sugg); } } @@ -196,19 +196,34 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { } } -fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { +fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { if let ExprKind::Lit(start_lit) = &start.kind && let ExprKind::Lit(end_lit) = &end.kind { - match (&start_lit.node, &end_lit.node) { - (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar, - (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar, - (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter, - (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter, - (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit, - _ => CharRange::Otherwise, - } + check_lit_range(start_lit, end_lit) + } else { + CharRange::Otherwise + } +} + + +fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange { + if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind + && let PatExprKind::Lit{ lit: end_lit, negated: false } = &end.kind + { + check_lit_range(start_lit, end_lit) } else { CharRange::Otherwise } } + +fn check_lit_range(start_lit: &Lit, end_lit: &Lit) -> CharRange { + match (&start_lit.node, &end_lit.node) { + (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar, + (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar, + (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter, + (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter, + (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit, + _ => CharRange::Otherwise, + } +} diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index ffa3eacf3544f..db65075e34fd4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; +use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; @@ -38,14 +38,13 @@ declare_clippy_lint! { } declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]); -fn expr_as_i128(expr: &Expr<'_>) -> Option { - if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind { - expr_as_i128(expr).map(|num| -num) - } else if let ExprKind::Lit(lit) = expr.kind +fn expr_as_i128(expr: &PatExpr<'_>) -> Option { + if let PatExprKind::Lit { lit, negated } = expr.kind && let LitKind::Int(num, _) = lit.node { // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now. - num.get().try_into().ok() + let n = i128::try_from(num.get()).ok()?; + Some(if negated { -n } else { n }) } else { None } @@ -58,7 +57,7 @@ struct Num { } impl Num { - fn new(expr: &Expr<'_>) -> Option { + fn new(expr: &PatExpr<'_>) -> Option { Some(Self { val: expr_as_i128(expr)?, span: expr.span, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index 69105ff0d5c7a..c910653ed7f82 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet}; use clippy_utils::sugg::Sugg; use rustc_ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, PatKind}; +use rustc_hir::{Arm, Expr, PatExprKind, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] if arms.len() == 2 { // no guards let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { - if let ExprKind::Lit(lit) = arm_bool.kind { + if let PatExprKind::Lit { lit, .. } = arm_bool.kind { match lit.node { LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), LitKind::Bool(false) => Some((arms[1].body, arms[0].body)), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 4b731d759723c..ba294bcae6992 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -7,7 +7,7 @@ use rustc_arena::DroplessArena; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; +use rustc_hir::{Arm, Expr, PatExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; @@ -313,7 +313,7 @@ impl<'a> NormalizedPat<'a> { }, PatKind::Lit(e) => match &e.kind { // TODO: Handle negative integers. They're currently treated as a wild match. - ExprKind::Lit(lit) => match lit.node { + PatExprKind::Lit{ lit, negated: false } => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), @@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> { let start = match start { None => 0, Some(e) => match &e.kind { - ExprKind::Lit(lit) => match lit.node { + PatExprKind::Lit { lit, negated: false } => match lit.node { LitKind::Int(val, _) => val.get(), LitKind::Char(val) => val.into(), LitKind::Byte(val) => val.into(), @@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> { let (end, bounds) = match end { None => (u128::MAX, RangeEnd::Included), Some(e) => match &e.kind { - ExprKind::Lit(lit) => match lit.node { + PatExprKind::Lit { lit, negated: false } => match lit.node { LitKind::Int(val, _) => (val.get(), bounds), LitKind::Char(val) => (val.into(), bounds), LitKind::Byte(val) => (val.into(), bounds), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 1267fc9d0a531..db4c22fcda315 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr}; -use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; @@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( }; for arm in arms { - if let PatKind::Lit(Expr { - kind: ExprKind::Lit(lit), + if let PatKind::Lit(PatExpr { + kind: PatExprKind::Lit { lit, negated: false }, .. }) = arm.pat.kind && let LitKind::Str(symbol, _) = lit.node diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index 63bea586caf61..ddf2c1cc89b77 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_> }, // compare match_expr ty with RetTy in `fn foo() -> RetTy` Node::Item(item) => { - if let ItemKind::Fn{ .. } = item.kind { + if let ItemKind::Fn { .. } = item.kind { let output = cx .tcx .fn_sig(item.owner_id) @@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }); }, // Example: `5 => 5` - (PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => { - if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind { + (PatKind::Lit(pat_expr_expr), ExprKind::Lit(expr_spanned)) => { + if let PatExprKind::Lit { + lit: pat_spanned, + negated: false, + } = &pat_expr_expr.kind + { return pat_spanned.node == expr_spanned.node; } }, diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index 856311899f268..ba677b423e27c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -34,13 +34,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs_const = if let Some(lhs) = lhs { - ConstEvalCtxt::new(cx).eval(lhs)? + ConstEvalCtxt::new(cx).eval_pat_expr(lhs)? } else { let min_val_const = ty.numeric_min_val(cx.tcx)?; mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))? }; let rhs_const = if let Some(rhs) = rhs { - ConstEvalCtxt::new(cx).eval(rhs)? + ConstEvalCtxt::new(cx).eval_pat_expr(rhs)? } else { let max_val_const = ty.numeric_max_val(cx.tcx)?; mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))? @@ -58,7 +58,9 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) } if let PatKind::Lit(value) = pat.kind { - let value = ConstEvalCtxt::new(cx).eval_full_int(value)?; + let value = ConstEvalCtxt::new(cx) + .eval_pat_expr(value)? + .int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?; return Some(SpannedRange { span: pat.span, node: (value, EndBound::Included(value)), diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 264458a86ef49..8243171a93557 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; +use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp, PatExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_span::{Span, Symbol, sym}; @@ -75,7 +75,7 @@ fn find_match_true<'tcx>( message: &'static str, ) { if let PatKind::Lit(lit) = pat.kind - && let ExprKind::Lit(lit) = lit.kind + && let PatExprKind::Lit{ lit, negated: false } = lit.kind && let LitKind::Bool(pat_is_true) = lit.node { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 10ca6832d9c12..1edd42969d270 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -9,7 +9,7 @@ use rustc_arena::DroplessArena; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_pat}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind, PatExpr, PatExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef}; use rustc_span::{Span, sym}; @@ -126,8 +126,8 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp // scrutinee derives PartialEq and the pattern is a constant. let pat_ref_count = match pat.kind { // string literals are already a reference. - PatKind::Lit(Expr { - kind: ExprKind::Lit(lit), + PatKind::Lit(PatExpr { + kind: PatExprKind::Lit { lit, negated: false }, .. }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, _ => pat_ref_count, diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 0d85b1b858a4f..048b67ed27623 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr}; use itertools::Itertools; use rustc_ast::{BinOpKind, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, PatKind}; +use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; @@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< return ControlFlow::Break(()); } if arm.pat.walk_short(|pat| match pat.kind { - PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => { + PatKind::Lit(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => { if let LitKind::Char(_) = lit.node { set_char_spans.push(lit.span); } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c2dcb5ae1f9e5..c92d5c0730c5a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, - FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, StructTailExpr, TyKind, + FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(expr); } + fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) { + let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind"); + macro_rules! kind { + ($($t:tt)*) => (kind(format_args!($($t)*))); + } + match lit.value.kind { + PatExprKind::Lit { lit, negated } => { + bind!(self, lit); + bind!(self, negated); + kind!("Lit{{ref {lit}, {negated} }}"); + self.lit(lit); + }, + PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"), + PatExprKind::Path(ref qpath) => { + bind!(self, qpath); + kind!("Path(ref {qpath})"); + self.qpath(qpath); + }, + } + } + fn pat(&self, pat: &Binding<&hir::Pat<'_>>) { let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind"); macro_rules! kind { @@ -721,13 +742,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { PatKind::Lit(lit_expr) => { bind!(self, lit_expr); kind!("Lit({lit_expr})"); - self.expr(lit_expr); + self.pat_expr(lit_expr); }, PatKind::Range(start, end, end_kind) => { opt_bind!(self, start, end); kind!("Range({start}, {end}, RangeEnd::{end_kind:?})"); - start.if_some(|e| self.expr(e)); - end.if_some(|e| self.expr(e)); + start.if_some(|e| self.pat_expr(e)); + end.if_some(|e| self.pat_expr(e)); }, PatKind::Slice(start, middle, end) => { bind!(self, start, end); diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 43ddf06730dd2..d46beddf73124 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -4,7 +4,6 @@ //! executable MIR bodies, so we have to do this instead. #![allow(clippy::float_cmp)] -use crate::macros::HirNode; use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; @@ -13,7 +12,7 @@ use rustc_apfloat::ieee::{Half, Quad}; 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, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind}; use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; @@ -442,30 +441,48 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } } + pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option> { + match &pat_expr.kind { + PatExprKind::Lit { lit, negated } => { + let ty = self.typeck.node_type_opt(pat_expr.hir_id); + let val = lit_to_mir_constant(&lit.node, ty); + if *negated { + self.constant_negate(&val, ty?) + } else { + Some(val) + } + } + PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value), + PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id), + } + } + + fn qpath(&self, qpath: &QPath<'_>, hir_id: HirId) -> Option> { + let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, hir_id).opt_def_id() { + self.tcx.crate_name(def_id.krate) == sym::core + } else { + false + }; + self.fetch_path_and_apply(qpath, hir_id, self.typeck.node_type(hir_id), |self_, result| { + let result = mir_to_const(self_.tcx, result)?; + // If source is already Constant we wouldn't want to override it with CoreConstant + self_.source.set( + if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) { + ConstantSource::CoreConstant + } else { + ConstantSource::Constant + }, + ); + Some(result) + }) + } + /// Simple constant folding: Insert an expression, get a constant or none. fn expr(&self, e: &Expr<'_>) -> Option> { match e.kind { ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), - ExprKind::Path(ref qpath) => { - let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() { - self.tcx.crate_name(def_id.krate) == sym::core - } else { - false - }; - self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| { - let result = mir_to_const(self_.tcx, result)?; - // If source is already Constant we wouldn't want to override it with CoreConstant - self_.source.set( - if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) { - ConstantSource::CoreConstant - } else { - ConstantSource::Constant - }, - ); - Some(result) - }) - }, + ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id), ExprKind::Block(block, _) => self.block(block), ExprKind::Lit(lit) => { if is_direct_expn_of(e.span, "cfg").is_some() { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7c4e834f8416f..b3b81412d08c3 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, - Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, - TyKind, + Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, + TraitBoundModifiers, Ty, TyKind, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> { li.name == ri.name && self.eq_pat(lp, rp) } + fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool { + match (&left.kind, &right.kind) { + ( + &PatExprKind::Lit { + lit: left, + negated: left_neg, + }, + &PatExprKind::Lit { + lit: right, + negated: right_neg, + }, + ) => left_neg == right_neg && left.node == right.node, + (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body), + (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right), + (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false, + } + } + /// Checks whether two patterns are the same. fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool { match (&left.kind, &right.kind) { @@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> { eq }, (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r), - (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r), + (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_pat_expr(l, r), (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)), (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => { - both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b)) - && both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b)) + both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b)) + && both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b)) && (li == ri) }, (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re), @@ -1073,6 +1091,18 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); } + pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) { + std::mem::discriminant(&lit.kind).hash(&mut self.s); + match &lit.kind { + PatExprKind::Lit { lit, negated } => { + lit.node.hash(&mut self.s); + negated.hash(&mut self.s); + }, + PatExprKind::ConstBlock(c) => self.hash_body(c.body), + PatExprKind::Path(qpath) => self.hash_qpath(qpath), + } + } + pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { @@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat), - PatKind::Lit(expr) => self.hash_expr(expr), + PatKind::Lit(expr) => self.hash_pat_expr(expr), PatKind::Or(pats) => { for pat in pats { self.hash_pat(pat); @@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { PatKind::Path(ref qpath) => self.hash_qpath(qpath), PatKind::Range(s, e, i) => { if let Some(s) = s { - self.hash_expr(s); + self.hash_pat_expr(s); } if let Some(e) = e { - self.hash_expr(e); + self.hash_pat_expr(e); } std::mem::discriminant(&i).hash(&mut self.s); }, diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout index a85dcddd3315f..a9b4c540377f4 100644 --- a/src/tools/clippy/tests/ui/author/if.stdout +++ b/src/tools/clippy/tests/ui/author/if.stdout @@ -31,7 +31,7 @@ if let StmtKind::Let(local) = stmt.kind if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind && let ExprKind::Let(let_expr) = cond.kind && let PatKind::Lit(lit_expr) = let_expr.pat.kind - && let ExprKind::Lit(ref lit) = lit_expr.kind + && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Bool(true) = lit.node && let ExprKind::Path(ref qpath) = let_expr.init.kind && match_qpath(qpath, &["a"]) diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout index 609d24910610c..c33e0d2cdee0b 100644 --- a/src/tools/clippy/tests/ui/author/loop.stdout +++ b/src/tools/clippy/tests/ui/author/loop.stdout @@ -77,7 +77,7 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While: } if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr) && let PatKind::Lit(lit_expr) = let_pat.kind - && let ExprKind::Lit(ref lit) = lit_expr.kind + && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Bool(true) = lit.node && let ExprKind::Path(ref qpath) = let_expr.kind && match_qpath(qpath, &["a"]) diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout index 91b3b6f6877eb..6c08110a3f1c2 100644 --- a/src/tools/clippy/tests/ui/author/matches.stdout +++ b/src/tools/clippy/tests/ui/author/matches.stdout @@ -5,13 +5,13 @@ if let StmtKind::Let(local) = stmt.kind && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node && arms.len() == 3 && let PatKind::Lit(lit_expr) = arms[0].pat.kind - && let ExprKind::Lit(ref lit1) = lit_expr.kind + && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node && arms[0].guard.is_none() && let ExprKind::Lit(ref lit2) = arms[0].body.kind && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node && let PatKind::Lit(lit_expr1) = arms[1].pat.kind - && let ExprKind::Lit(ref lit3) = lit_expr1.kind + && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node && arms[1].guard.is_none() && let ExprKind::Block(block, None) = arms[1].body.kind diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout index 0b332d5e7d0e1..46f68cb79b042 100644 --- a/src/tools/clippy/tests/ui/author/struct.stdout +++ b/src/tools/clippy/tests/ui/author/struct.stdout @@ -24,7 +24,7 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind && fields.len() == 1 && fields[0].ident.as_str() == "field" && let PatKind::Lit(lit_expr) = fields[0].pat.kind - && let ExprKind::Lit(ref lit) = lit_expr.kind + && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && arm.guard.is_none() && let ExprKind::Block(block, None) = arm.body.kind @@ -37,7 +37,7 @@ if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind && match_qpath(qpath, &["TestTuple"]) && fields.len() == 1 && let PatKind::Lit(lit_expr) = fields[0].kind - && let ExprKind::Lit(ref lit) = lit_expr.kind + && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && arm.guard.is_none() && let ExprKind::Block(block, None) = arm.body.kind diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout index c424b1afa3465..43aa93c83bd31 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout @@ -14,4 +14,4 @@ extern crate std; fn main() ({ } as ()) -fn foo((-(128 as i8) as i8)...(127 as i8): i8) ({ } as ()) +fn foo(-128...127: i8) ({ } as ()) From 4a8773a3afce505ee861ba342ff9217caf9dfee8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 7 Jan 2025 08:56:23 +0000 Subject: [PATCH 101/189] Rename PatKind::Lit to Expr --- compiler/rustc_ast/src/ast.rs | 6 +++--- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/pat.rs | 4 ++-- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_expand/src/base.rs | 2 +- compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_hir/src/hir.rs | 8 ++++---- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/check/region.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 4 ++-- compiler/rustc_hir_typeck/src/pat.rs | 8 ++++---- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_parse/src/parser/pat.rs | 12 ++++++------ compiler/rustc_passes/src/input_stats.rs | 4 ++-- src/librustdoc/clean/utils.rs | 4 ++-- .../clippy_lints/src/default_numeric_fallback.rs | 2 +- .../clippy/clippy_lints/src/equatable_if_let.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- .../clippy/clippy_lints/src/manual_range_patterns.rs | 2 +- .../clippy/clippy_lints/src/matches/match_bool.rs | 2 +- .../clippy_lints/src/matches/match_same_arms.rs | 6 +++--- .../src/matches/match_str_case_mismatch.rs | 2 +- .../clippy_lints/src/matches/needless_match.rs | 2 +- .../clippy_lints/src/matches/overlapping_arms.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 6 +++--- .../clippy/clippy_lints/src/matches/single_match.rs | 8 ++++---- src/tools/clippy/clippy_lints/src/string_patterns.rs | 2 +- .../clippy/clippy_lints/src/unnested_or_patterns.rs | 4 ++-- src/tools/clippy/clippy_lints/src/utils/author.rs | 6 +++--- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 2 +- src/tools/clippy/clippy_utils/src/hir_utils.rs | 4 ++-- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/clippy/tests/ui/author/if.stdout | 2 +- src/tools/clippy/tests/ui/author/loop.stdout | 2 +- src/tools/clippy/tests/ui/author/matches.stdout | 4 ++-- src/tools/clippy/tests/ui/author/struct.stdout | 4 ++-- src/tools/rustfmt/src/patterns.rs | 6 +++--- tests/ui/macros/stringify.rs | 2 +- tests/ui/pattern/patkind-litrange-no-expr.rs | 2 +- tests/ui/unpretty/expanded-exhaustive.rs | 4 ++-- tests/ui/unpretty/expanded-exhaustive.stdout | 4 ++-- 45 files changed, 79 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3a81b93d157ce..8e73df63ef54f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -623,7 +623,7 @@ impl Pat { PatKind::Wild | PatKind::Rest | PatKind::Never - | PatKind::Lit(_) + | PatKind::Expr(_) | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) @@ -801,8 +801,8 @@ pub enum PatKind { /// A reference pattern (e.g., `&mut (a, b)`). Ref(P, Mutability), - /// A literal. - Lit(P), + /// A literal, const block or path. + Expr(P), /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). Range(Option>, Option>, Spanned), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 04cdfc93dcb15..aa88e8369d5b6 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1512,7 +1512,7 @@ pub fn walk_pat(vis: &mut T, pat: &mut P) { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); } - PatKind::Lit(e) => vis.visit_expr(e), + PatKind::Expr(e) => vis.visit_expr(e), PatKind::TupleStruct(qself, path, elems) => { vis.visit_qself(qself); vis.visit_path(path); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e99fc7b604e31..1d6d7330757de 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -680,7 +680,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } - PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), + PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)), PatKind::Range(lower_bound, upper_bound, _end) => { visit_opt!(visitor, visit_expr, lower_bound); visit_opt!(visitor, visit_expr, upper_bound); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 27b8bdefb0554..abd314ae74c39 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -38,8 +38,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lower_sub, ); } - PatKind::Lit(e) => { - break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); + PatKind::Expr(e) => { + break hir::PatKind::Expr(self.lower_expr_within_pat(e, false)); } PatKind::TupleStruct(qself, path, pats) => { let qpath = self.lower_qpath( diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 172df10292920..9b958ed6b0d6b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1701,7 +1701,7 @@ impl<'a> State<'a> { self.print_pat(inner); } } - PatKind::Lit(e) => self.print_expr(e, FixupContext::default()), + PatKind::Expr(e) => self.print_expr(e, FixupContext::default()), PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => { if let Some(e) = begin { self.print_expr(e, FixupContext::default()); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e6adbc0f0ac89..43feab94c01d9 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -522,7 +522,7 @@ impl MacResult for MacEager { return Some(P(ast::Pat { id: ast::DUMMY_NODE_ID, span: e.span, - kind: PatKind::Lit(e), + kind: PatKind::Expr(e), tokens: None, })); } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 22bfda34cc0e5..8bf09cf96b3f7 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -486,7 +486,7 @@ impl<'a> ExtCtxt<'a> { self.pat(span, PatKind::Wild) } pub fn pat_lit(&self, span: Span, expr: P) -> P { - self.pat(span, PatKind::Lit(expr)) + self.pat(span, PatKind::Expr(expr)) } pub fn pat_ident(&self, span: Span, ident: Ident) -> P { self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4d452d6cb3732..951e95a6385d0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1386,7 +1386,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, + Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), @@ -1413,7 +1413,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} + Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), @@ -1583,8 +1583,8 @@ pub enum PatKind<'hir> { /// A reference pattern (e.g., `&mut (a, b)`). Ref(&'hir Pat<'hir>, Mutability), - /// A literal. - Lit(&'hir PatExpr<'hir>), + /// A literal, const block or path. + Expr(&'hir PatExpr<'hir>), /// A guard pattern (e.g., `x if guard(x)`). Guard(&'hir Pat<'hir>, &'hir Expr<'hir>), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b832843aa6e2f..ef863aca09052 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -688,7 +688,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } - PatKind::Lit(ref expression) => try_visit!(visitor.visit_pat_expr(expression)), + PatKind::Expr(ref expression) => try_visit!(visitor.visit_pat_expr(expression)), PatKind::Range(ref lower_bound, ref upper_bound, _) => { visit_opt!(visitor, visit_pat_expr, lower_bound); visit_opt!(visitor, visit_pat_expr, upper_bound); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index ffc0657eebf1d..e5f98bdfb7fed 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -704,7 +704,7 @@ fn resolve_local<'tcx>( | PatKind::Wild | PatKind::Never | PatKind::Path(_) - | PatKind::Lit(_) + | PatKind::Expr(_) | PatKind::Range(_, _, _) | PatKind::Err(_) => false, } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 632a12b2c3fd4..39b6823cf0e0c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1980,7 +1980,7 @@ impl<'a> State<'a> { self.pclose(); } } - PatKind::Lit(e) => self.print_pat_expr(e), + PatKind::Expr(e) => self.print_pat_expr(e), PatKind::Range(begin, end, end_kind) => { if let Some(expr) = begin { self.print_pat_expr(expr); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index ca4be850a8edd..3bb518e7f9711 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::PatKind::Box(_) | hir::PatKind::Ref(_, _) | hir::PatKind::Deref(_) - | hir::PatKind::Lit(_) + | hir::PatKind::Expr(_) | hir::PatKind::Range(_, _, _) | hir::PatKind::Slice(_, _, _) | hir::PatKind::Err(_) => true, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index ad764e5563b94..1f48b703e4ac8 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -595,7 +595,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let place_ty = place.place.ty(); needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span); } - PatKind::Lit(_) | PatKind::Range(..) => { + PatKind::Expr(_) | PatKind::Range(..) => { // If the PatKind is a Lit or a Range then we want // to borrow discr. needs_to_be_read = true; @@ -1803,7 +1803,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx PatKind::Path(_) | PatKind::Binding(.., None) - | PatKind::Lit(..) + | PatKind::Expr(..) | PatKind::Range(..) | PatKind::Never | PatKind::Wild diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c8a04c331a2cc..36094657eafd1 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Wild | PatKind::Err(_) => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. PatKind::Never => expected, - PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), + PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), PatKind::Binding(ba, var_id, ident, sub) => { self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) @@ -399,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // // Call `resolve_vars_if_possible` here for inline const blocks. - PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() { + PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() { ty::Ref(..) => AdjustMode::Pass, _ => AdjustMode::Peel, }, @@ -943,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Box(..) | PatKind::Deref(_) | PatKind::Ref(..) - | PatKind::Lit(..) + | PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) => break 'block None, }, @@ -1837,7 +1837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else if inexistent_fields.len() == 1 { match pat_field.pat.kind { - PatKind::Lit(_) + PatKind::Expr(_) if !self.may_coerce( self.typeck_results.borrow().node_type(pat_field.pat.hir_id), self.field_ty(field.span, field_def, args), diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 8b1526bc747d4..3059adb3fda10 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1220,7 +1220,7 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {}, + | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false, keep_space); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 305019bc9fcb5..242b62dfa8dde 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -324,7 +324,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Lit(value) => self.lower_lit(value), + hir::PatKind::Expr(value) => self.lower_lit(value), hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 5ad3da2196f8f..64bcb1a5a36cc 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -656,14 +656,14 @@ impl<'a> Parser<'a> { fn visit_pat(&mut self, p: &'a Pat) -> Self::Result { match &p.kind { // Base expression - PatKind::Err(_) | PatKind::Lit(_) => { + PatKind::Err(_) | PatKind::Expr(_) => { self.maybe_add_suggestions_then_emit(p.span, p.span, false) } // Sub-patterns // FIXME: this doesn't work with recursive subpats (`&mut &mut `) PatKind::Box(subpat) | PatKind::Ref(subpat, _) - if matches!(subpat.kind, PatKind::Err(_) | PatKind::Lit(_)) => + if matches!(subpat.kind, PatKind::Err(_) | PatKind::Expr(_)) => { self.maybe_add_suggestions_then_emit(subpat.span, p.span, false) } @@ -766,7 +766,7 @@ impl<'a> Parser<'a> { if let Some(re) = self.parse_range_end() { self.parse_pat_range_begin_with(const_expr, re)? } else { - PatKind::Lit(const_expr) + PatKind::Expr(const_expr) } } else if self.is_builtin() { self.parse_pat_builtin()? @@ -833,7 +833,7 @@ impl<'a> Parser<'a> { .struct_span_err(self_.token.span, msg) .with_span_label(self_.token.span, format!("expected {expected}")) }); - PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) + PatKind::Expr(self.mk_expr(lo, ExprKind::Lit(lit))) } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { @@ -845,7 +845,7 @@ impl<'a> Parser<'a> { match self.parse_range_end() { Some(form) => self.parse_pat_range_begin_with(begin, form)?, - None => PatKind::Lit(begin), + None => PatKind::Expr(begin), } } Err(err) => return self.fatal_unexpected_non_pat(err, expected), @@ -989,7 +989,7 @@ impl<'a> Parser<'a> { match &pat.kind { // recover ranges with parentheses around the `(start)..` - PatKind::Lit(begin) + PatKind::Expr(begin) if self.may_recover() && let Some(form) = self.parse_range_end() => { diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 88d69eb36788d..6617cf2f723a9 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -304,7 +304,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Box, Deref, Ref, - Lit, + Expr, Guard, Range, Slice, @@ -587,7 +587,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Box, Deref, Ref, - Lit, + Expr, Range, Slice, Rest, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 1fb35750c15f5..99e88f878fba6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -314,9 +314,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { PatKind::Box(p) => return name_from_pat(p), PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)), PatKind::Ref(p, _) => return name_from_pat(p), - PatKind::Lit(..) => { + PatKind::Expr(..) => { warn!( - "tried to get argument name from PatKind::Lit, which is silly in function arguments" + "tried to get argument name from PatKind::Expr, which is silly in function arguments" ); return Symbol::intern("()"); } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index f579c9a41828c..c04a73c890f0e 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -224,7 +224,7 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { fn visit_pat(&mut self, pat: &'tcx Pat<'_>) { match pat.kind { - PatKind::Lit(&PatExpr { + PatKind::Expr(&PatExpr { hir_id, kind: PatExprKind::Lit { lit, .. }, .. diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 9c8edfd6113f6..8a5cf7f56d5f6 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), - PatKind::Path(_) | PatKind::Lit(_) => true, + PatKind::Path(_) | PatKind::Expr(_) => true, } } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index d6c1cb5e6e439..1c63ca9d97435 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let ExprKind::Let(lt) = expr.kind && match lt.pat.kind { PatKind::Slice([], None, []) => true, - PatKind::Lit(lit) => match lit.kind { + PatKind::Expr(lit) => match lit.kind { PatExprKind::Lit { lit, .. } => match lit.node { LitKind::Str(lit, _) => lit.as_str().is_empty(), _ => false, diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index db65075e34fd4..2e5a92915d9ca 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -89,7 +89,7 @@ impl LateLintPass<'_> for ManualRangePatterns { let mut ranges_found = Vec::new(); for pat in pats { - if let PatKind::Lit(lit) = pat.kind + if let PatKind::Expr(lit) = pat.kind && let Some(num) = Num::new(lit) { numbers_found.insert(num.val); diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index c910653ed7f82..7e43d222a6623 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -21,7 +21,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] move |diag| { if arms.len() == 2 { // no guards - let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { + let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { if let PatExprKind::Lit { lit, .. } = arm_bool.kind { match lit.node { LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index ba294bcae6992..28e05c273d5c7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -7,7 +7,7 @@ use rustc_arena::DroplessArena; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Arm, Expr, PatExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; +use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd}; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; @@ -311,9 +311,9 @@ impl<'a> NormalizedPat<'a> { ); Self::Tuple(None, pats) }, - PatKind::Lit(e) => match &e.kind { + PatKind::Expr(e) => match &e.kind { // TODO: Handle negative integers. They're currently treated as a wild match. - PatExprKind::Lit{ lit, negated: false } => match lit.node { + PatExprKind::Lit { lit, negated: false } => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index db4c22fcda315..9f5b7c855a139 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -85,7 +85,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( }; for arm in arms { - if let PatKind::Lit(PatExpr { + if let PatKind::Expr(PatExpr { kind: PatExprKind::Lit { lit, negated: false }, .. }) = arm.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index ddf2c1cc89b77..0d5575efc2209 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -189,7 +189,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }); }, // Example: `5 => 5` - (PatKind::Lit(pat_expr_expr), ExprKind::Lit(expr_spanned)) => { + (PatKind::Expr(pat_expr_expr), ExprKind::Lit(expr_spanned)) => { if let PatExprKind::Lit { lit: pat_spanned, negated: false, diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index ba677b423e27c..4a5d3c516b880 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -57,7 +57,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) }); } - if let PatKind::Lit(value) = pat.kind { + if let PatKind::Expr(value) = pat.kind { let value = ConstEvalCtxt::new(cx) .eval_pat_expr(value)? .int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?; diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 8243171a93557..7e74b36b44158 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp, PatExprKind}; +use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_span::{Span, Symbol, sym}; @@ -74,8 +74,8 @@ fn find_match_true<'tcx>( span: Span, message: &'static str, ) { - if let PatKind::Lit(lit) = pat.kind - && let PatExprKind::Lit{ lit, negated: false } = lit.kind + if let PatKind::Expr(lit) = pat.kind + && let PatExprKind::Lit { lit, negated: false } = lit.kind && let LitKind::Bool(pat_is_true) = lit.node { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 1edd42969d270..b1d0686ffc42e 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -9,7 +9,7 @@ use rustc_arena::DroplessArena; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_pat}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind, PatExpr, PatExprKind}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef}; use rustc_span::{Span, sym}; @@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp } let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat); - let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind + let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait() && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait() @@ -126,7 +126,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp // scrutinee derives PartialEq and the pattern is a constant. let pat_ref_count = match pat.kind { // string literals are already a reference. - PatKind::Lit(PatExpr { + PatKind::Expr(PatExpr { kind: PatExprKind::Lit { lit, negated: false }, .. }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, @@ -384,7 +384,7 @@ impl<'a> PatState<'a> { PatKind::Wild | PatKind::Binding(_, _, _, None) - | PatKind::Lit(_) + | PatKind::Expr(_) | PatKind::Range(..) | PatKind::Path(_) | PatKind::Never diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 048b67ed27623..3834087f79779 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< return ControlFlow::Break(()); } if arm.pat.walk_short(|pat| match pat.kind { - PatKind::Lit(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => { + PatKind::Expr(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => { if let LitKind::Char(_) = lit.node { set_char_spans.push(lit.span); } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 50a97579df779..8923484bb58f0 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -92,7 +92,7 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { - if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind { + if let Ident(.., None) | Expr(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind { // This is a leaf pattern, so cloning is unprofitable. return; } @@ -228,7 +228,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Expr(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index c92d5c0730c5a..4dcc8ac7fb0af 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -738,10 +738,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Guard({pat}, {cond})"); self.pat(pat); self.expr(cond); - } - PatKind::Lit(lit_expr) => { + }, + PatKind::Expr(lit_expr) => { bind!(self, lit_expr); - kind!("Lit({lit_expr})"); + kind!("Expr({lit_expr})"); self.pat_expr(lit_expr); }, PatKind::Range(start, end, end_kind) => { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 623d9c7608612..2eb09bac8d881 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -36,7 +36,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { (Paren(l), _) => eq_pat(l, r), (_, Paren(r)) => eq_pat(l, r), (Wild, Wild) | (Rest, Rest) => true, - (Lit(l), Lit(r)) => eq_expr(l, r), + (Expr(l), Expr(r)) => eq_expr(l, r), (Ident(b1, i1, s1), Ident(b2, i2, s2)) => { b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat) }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index b3b81412d08c3..d1d0abd469093 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -525,7 +525,7 @@ impl HirEqInterExpr<'_, '_, '_> { eq }, (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r), - (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_pat_expr(l, r), + (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r), (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)), (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => { both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b)) @@ -1114,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat), - PatKind::Lit(expr) => self.hash_pat_expr(expr), + PatKind::Expr(expr) => self.hash_pat_expr(expr), PatKind::Or(pats) => { for pat in pats { self.hash_pat(pat); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ba4a0f44584ef..d42e40acbc081 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1777,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true, + PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true, } } diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout index a9b4c540377f4..8ffdf8862027b 100644 --- a/src/tools/clippy/tests/ui/author/if.stdout +++ b/src/tools/clippy/tests/ui/author/if.stdout @@ -30,7 +30,7 @@ if let StmtKind::Let(local) = stmt.kind } if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind && let ExprKind::Let(let_expr) = cond.kind - && let PatKind::Lit(lit_expr) = let_expr.pat.kind + && let PatKind::Expr(lit_expr) = let_expr.pat.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Bool(true) = lit.node && let ExprKind::Path(ref qpath) = let_expr.init.kind diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout index c33e0d2cdee0b..c94eb171f52b9 100644 --- a/src/tools/clippy/tests/ui/author/loop.stdout +++ b/src/tools/clippy/tests/ui/author/loop.stdout @@ -76,7 +76,7 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While: // report your lint here } if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr) - && let PatKind::Lit(lit_expr) = let_pat.kind + && let PatKind::Expr(lit_expr) = let_pat.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Bool(true) = lit.node && let ExprKind::Path(ref qpath) = let_expr.kind diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout index 6c08110a3f1c2..acb3b140dfa13 100644 --- a/src/tools/clippy/tests/ui/author/matches.stdout +++ b/src/tools/clippy/tests/ui/author/matches.stdout @@ -4,13 +4,13 @@ if let StmtKind::Let(local) = stmt.kind && let ExprKind::Lit(ref lit) = scrutinee.kind && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node && arms.len() == 3 - && let PatKind::Lit(lit_expr) = arms[0].pat.kind + && let PatKind::Expr(lit_expr) = arms[0].pat.kind && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node && arms[0].guard.is_none() && let ExprKind::Lit(ref lit2) = arms[0].body.kind && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node - && let PatKind::Lit(lit_expr1) = arms[1].pat.kind + && let PatKind::Expr(lit_expr1) = arms[1].pat.kind && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node && arms[1].guard.is_none() diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout index 46f68cb79b042..b66bbccb3cf1b 100644 --- a/src/tools/clippy/tests/ui/author/struct.stdout +++ b/src/tools/clippy/tests/ui/author/struct.stdout @@ -23,7 +23,7 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind && match_qpath(qpath, &["Test"]) && fields.len() == 1 && fields[0].ident.as_str() == "field" - && let PatKind::Lit(lit_expr) = fields[0].pat.kind + && let PatKind::Expr(lit_expr) = fields[0].pat.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && arm.guard.is_none() @@ -36,7 +36,7 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind && match_qpath(qpath, &["TestTuple"]) && fields.len() == 1 - && let PatKind::Lit(lit_expr) = fields[0].kind + && let PatKind::Expr(lit_expr) = fields[0].kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && arm.guard.is_none() diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 7b4730eadc854..b55469f332aa1 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -42,7 +42,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool { | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) - | ast::PatKind::Lit(_) => true, + | ast::PatKind::Expr(_) => true, ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -293,7 +293,7 @@ impl Rewrite for Pat { let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?; rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape) } - PatKind::Lit(ref expr) => expr.rewrite_result(context, shape), + PatKind::Expr(ref expr) => expr.rewrite_result(context, shape), PatKind::Slice(ref slice_pat) if context.config.style_edition() <= StyleEdition::Edition2021 => { @@ -530,7 +530,7 @@ pub(crate) fn can_be_overflowed_pat( ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => { can_be_overflowed_pat(context, &TuplePatField::Pat(p), len) } - ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len), + ast::PatKind::Expr(ref expr) => can_be_overflowed_expr(context, expr, len), _ => false, }, TuplePatField::Dotdot(..) => false, diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index a560bf4c6ef43..40033f546d30b 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -569,7 +569,7 @@ fn test_pat() { c1!(pat, [ &pat ], "&pat"); c1!(pat, [ &mut pat ], "&mut pat"); - // PatKind::Lit + // PatKind::Expr c1!(pat, [ 1_000_i8 ], "1_000_i8"); // PatKind::Range diff --git a/tests/ui/pattern/patkind-litrange-no-expr.rs b/tests/ui/pattern/patkind-litrange-no-expr.rs index 7ef541cb58528..14d7dc737d652 100644 --- a/tests/ui/pattern/patkind-litrange-no-expr.rs +++ b/tests/ui/pattern/patkind-litrange-no-expr.rs @@ -6,7 +6,7 @@ macro_rules! enum_number { fn foo(value: i32) -> Option<$name> { match value { - $( $value => Some($name::$variant), )* // PatKind::Lit + $( $value => Some($name::$variant), )* // PatKind::Expr $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range _ => None } diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index e052627e71cfe..26c253d049b24 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -651,8 +651,8 @@ mod patterns { let &mut pat; } - /// PatKind::Lit - fn pat_lit() { + /// PatKind::Expr + fn pat_expr() { let 1_000_i8; let -""; } diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 132d00cd8edd5..bd7aa1117cce1 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -567,8 +567,8 @@ mod patterns { fn pat_deref() { let deref!(pat); } /// PatKind::Ref fn pat_ref() { let &pat; let &mut pat; } - /// PatKind::Lit - fn pat_lit() { let 1_000_i8; let -""; } + /// PatKind::Expr + fn pat_expr() { let 1_000_i8; let -""; } /// PatKind::Range fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; } /// PatKind::Slice From 6f1c4177e725d044871e17c0bdcafe4cc4a3b4ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 6 Jan 2025 13:17:13 +0000 Subject: [PATCH 102/189] stop calling `DenseLocationMap` "elements" "Elements" are `RegionElement`s. The dense location mapping was removed from the element containers a while ago but didn't rename its use-sites. Most of the old naming only used the mapping, and are better named `location_map`. --- compiler/rustc_borrowck/src/nll.rs | 6 +-- .../rustc_borrowck/src/region_infer/mod.rs | 4 +- .../rustc_borrowck/src/region_infer/values.rs | 53 ++++++++++--------- .../src/type_check/liveness/local_use_map.rs | 8 +-- .../src/type_check/liveness/mod.rs | 4 +- .../src/type_check/liveness/trace.rs | 43 ++++++++------- compiler/rustc_borrowck/src/type_check/mod.rs | 8 +-- 7 files changed, 65 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 7ae1df9522fb8..8f436dcdb07cc 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -94,7 +94,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( let mut all_facts = (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); - let elements = Rc::new(DenseLocationMap::new(body)); + let location_map = Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. let MirTypeckResults { @@ -112,7 +112,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( &mut all_facts, flow_inits, move_data, - Rc::clone(&elements), + Rc::clone(&location_map), ); // Create the region inference context, taking ownership of the @@ -137,7 +137,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( var_infos, constraints, universal_region_relations, - elements, + location_map, ); // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 1e29b7418540c..86dc6697c2ebc 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -396,7 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { var_infos: VarInfos, constraints: MirTypeckRegionConstraints<'tcx>, universal_region_relations: Frozen>, - elements: Rc, + location_map: Rc, ) -> Self { let universal_regions = &universal_region_relations.universal_regions; let MirTypeckRegionConstraints { @@ -440,7 +440,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut scc_values = - RegionValues::new(elements, universal_regions.len(), placeholder_indices); + RegionValues::new(location_map, universal_regions.len(), placeholder_indices); for region in liveness_constraints.regions() { let scc = constraint_sccs.scc(region); diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 75aef8b303ba8..11fb125ca2281 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -38,7 +38,7 @@ pub(crate) enum RegionElement { /// an interval matrix storing liveness ranges for each region-vid. pub(crate) struct LivenessValues { /// The map from locations to points. - elements: Rc, + location_map: Rc, /// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and /// currently only used for validating promoteds (which don't care about more precise tracking). @@ -77,11 +77,11 @@ impl LiveLoans { impl LivenessValues { /// Create an empty map of regions to locations where they're live. - pub(crate) fn with_specific_points(elements: Rc) -> Self { + pub(crate) fn with_specific_points(location_map: Rc) -> Self { LivenessValues { live_regions: None, - points: Some(SparseIntervalMatrix::new(elements.num_points())), - elements, + points: Some(SparseIntervalMatrix::new(location_map.num_points())), + location_map, loans: None, } } @@ -90,11 +90,11 @@ impl LivenessValues { /// /// Unlike `with_specific_points`, does not track exact locations where something is live, only /// which regions are live. - pub(crate) fn without_specific_points(elements: Rc) -> Self { + pub(crate) fn without_specific_points(location_map: Rc) -> Self { LivenessValues { live_regions: Some(Default::default()), points: None, - elements, + location_map, loans: None, } } @@ -122,11 +122,11 @@ impl LivenessValues { /// Records `region` as being live at the given `location`. pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) { - let point = self.elements.point_from_location(location); + let point = self.location_map.point_from_location(location); debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); if let Some(points) = &mut self.points { points.insert(region, point); - } else if self.elements.point_in_range(point) { + } else if self.location_map.point_in_range(point) { self.live_regions.as_mut().unwrap().insert(region); } @@ -143,7 +143,7 @@ impl LivenessValues { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); if let Some(this) = &mut self.points { this.union_row(region, points); - } else if points.iter().any(|point| self.elements.point_in_range(point)) { + } else if points.iter().any(|point| self.location_map.point_in_range(point)) { self.live_regions.as_mut().unwrap().insert(region); } @@ -170,7 +170,7 @@ impl LivenessValues { /// Returns whether `region` is marked live at the given `location`. pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool { - let point = self.elements.point_from_location(location); + let point = self.location_map.point_from_location(location); if let Some(points) = &self.points { points.row(region).is_some_and(|r| r.contains(point)) } else { @@ -191,25 +191,26 @@ impl LivenessValues { .row(region) .into_iter() .flat_map(|set| set.iter()) - .take_while(|&p| self.elements.point_in_range(p)) + .take_while(|&p| self.location_map.point_in_range(p)) } /// For debugging purposes, returns a pretty-printed string of the points where the `region` is /// live. pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String { pretty_print_region_elements( - self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))), + self.live_points(region) + .map(|p| RegionElement::Location(self.location_map.to_location(p))), ) } #[inline] pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { - self.elements.point_from_location(location) + self.location_map.point_from_location(location) } #[inline] pub(crate) fn location_from_point(&self, point: PointIndex) -> Location { - self.elements.to_location(point) + self.location_map.to_location(point) } /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`. @@ -272,7 +273,7 @@ impl PlaceholderIndices { /// because (since it is returned) it must live for at least `'a`. But /// it would also contain various points from within the function. pub(crate) struct RegionValues { - elements: Rc, + location_map: Rc, placeholder_indices: PlaceholderIndices, points: SparseIntervalMatrix, free_regions: SparseBitMatrix, @@ -287,14 +288,14 @@ impl RegionValues { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. pub(crate) fn new( - elements: Rc, + location_map: Rc, num_universal_regions: usize, placeholder_indices: PlaceholderIndices, ) -> Self { - let num_points = elements.num_points(); + let num_points = location_map.num_points(); let num_placeholders = placeholder_indices.len(); Self { - elements, + location_map, points: SparseIntervalMatrix::new(num_points), placeholder_indices, free_regions: SparseBitMatrix::new(num_universal_regions), @@ -336,7 +337,7 @@ impl RegionValues { end: usize, ) -> Option { let row = self.points.row(r)?; - let block = self.elements.entry_point(block); + let block = self.location_map.entry_point(block); let start = block.plus(start); let end = block.plus(end); let first_unset = row.first_unset_in(start..=end)?; @@ -375,8 +376,8 @@ impl RegionValues { pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { self.points.row(r).into_iter().flat_map(move |set| { set.iter() - .take_while(move |&p| self.elements.point_in_range(p)) - .map(move |p| self.elements.to_location(p)) + .take_while(move |&p| self.location_map.point_in_range(p)) + .map(move |p| self.location_map.to_location(p)) }) } @@ -430,12 +431,12 @@ pub(crate) trait ToElementIndex: Debug + Copy { impl ToElementIndex for Location { fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.elements.point_from_location(self); + let index = values.location_map.point_from_location(self); values.points.insert(row, index) } fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.elements.point_from_location(self); + let index = values.location_map.point_from_location(self); values.points.contains(row, index) } } @@ -464,14 +465,14 @@ impl ToElementIndex for ty::PlaceholderRegion { /// For debugging purposes, returns a pretty-printed string of the given points. pub(crate) fn pretty_print_points( - elements: &DenseLocationMap, + location_map: &DenseLocationMap, points: impl IntoIterator, ) -> String { pretty_print_region_elements( points .into_iter() - .take_while(|&p| elements.point_in_range(p)) - .map(|p| elements.to_location(p)) + .take_while(|&p| location_map.point_in_range(p)) + .map(|p| location_map.to_location(p)) .map(RegionElement::Location), ) } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index 695a1cdac0d79..6182b68f6f411 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -82,7 +82,7 @@ impl<'a> Iterator for AppearancesIter<'a> { impl LocalUseMap { pub(crate) fn build( live_locals: &[Local], - elements: &DenseLocationMap, + location_map: &DenseLocationMap, body: &Body<'_>, ) -> Self { let nones = IndexVec::from_elem(None, &body.local_decls); @@ -101,7 +101,7 @@ impl LocalUseMap { IndexVec::from_elem(false, &body.local_decls); live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); - LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } + LocalUseMapBuild { local_use_map: &mut local_use_map, location_map, locals_with_use_data } .visit_body(body); local_use_map @@ -125,7 +125,7 @@ impl LocalUseMap { struct LocalUseMapBuild<'me> { local_use_map: &'me mut LocalUseMap, - elements: &'me DenseLocationMap, + location_map: &'me DenseLocationMap, // Vector used in `visit_local` to signal which `Local`s do we need // def/use/drop information on, constructed from `live_locals` (that @@ -147,7 +147,7 @@ impl Visitor<'_> for LocalUseMapBuild<'_> { DefUse::Use => &mut self.local_use_map.first_use_at[local], DefUse::Drop => &mut self.local_use_map.first_drop_at[local], }; - let point_index = self.elements.point_from_location(location); + let point_index = self.location_map.point_from_location(location); let appearance_index = self .local_use_map .appearances diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 3e9900cce5f57..f23602d03588f 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -32,7 +32,7 @@ mod trace; pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &DenseLocationMap, + location_map: &DenseLocationMap, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { @@ -49,7 +49,7 @@ pub(super) fn generate<'a, 'tcx>( trace::trace( typeck, body, - elements, + location_map, flow_inits, move_data, relevant_live_locals, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index c7a2d32b31dc8..2e09821b358a8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -37,13 +37,13 @@ use crate::type_check::{NormalizeLocation, TypeChecker}; pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &DenseLocationMap, + location_map: &DenseLocationMap, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, boring_locals: Vec, ) { - let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body); + let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body); // When using `-Zpolonius=next`, compute the set of loans that can reach a given region. if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { @@ -79,7 +79,7 @@ pub(super) fn trace<'a, 'tcx>( typeck, body, flow_inits, - elements, + location_map, local_use_map, move_data, drop_data: FxIndexMap::default(), @@ -100,7 +100,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> { typeck: &'a mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping - elements: &'a DenseLocationMap, + location_map: &'a DenseLocationMap, /// MIR we are analyzing. body: &'a Body<'tcx>, @@ -149,7 +149,7 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> { impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self { - let num_points = cx.elements.num_points(); + let num_points = cx.location_map.num_points(); LivenessResults { cx, defs: BitSet::new_empty(num_points), @@ -240,7 +240,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { .collect() }; - let live_at = IntervalSet::new(self.cx.elements.num_points()); + let live_at = IntervalSet::new(self.cx.location_map.num_points()); for (local, local_ty, location) in facts_to_add { self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at); } @@ -279,7 +279,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { // * Inclusively, the block start // * Exclusively, the previous definition (if it's in this block) // * Exclusively, the previous live_at setting (an optimization) - let block_start = self.cx.elements.to_block_start(p); + let block_start = self.cx.location_map.to_block_start(p); let previous_defs = self.defs.last_set_in(block_start..=p); let previous_live_at = self.use_live_at.last_set_in(block_start..=p); @@ -303,12 +303,12 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { // terminators of predecessor basic blocks. Push those onto the // stack so that the next iteration(s) will process them. - let block = self.cx.elements.to_location(block_start).block; + let block = self.cx.location_map.to_location(block_start).block; self.stack.extend( self.cx.body.basic_blocks.predecessors()[block] .iter() .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) - .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)), + .map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)), ); } } @@ -331,7 +331,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { // Find the drops where `local` is initialized. for drop_point in self.cx.local_use_map.drops(local) { - let location = self.cx.elements.to_location(drop_point); + let location = self.cx.location_map.to_location(drop_point); debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); if self.cx.initialized_at_terminator(location.block, mpi) @@ -367,7 +367,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { debug!( "compute_drop_live_points_for_block(mpi={:?}, term_point={:?})", self.cx.move_data.move_paths[mpi].place, - self.cx.elements.to_location(term_point), + self.cx.location_map.to_location(term_point), ); // We are only invoked with terminators where `mpi` is @@ -377,12 +377,15 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { // Otherwise, scan backwards through the statements in the // block. One of them may be either a definition or use // live point. - let term_location = self.cx.elements.to_location(term_point); + let term_location = self.cx.location_map.to_location(term_point); debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,); let block = term_location.block; - let entry_point = self.cx.elements.entry_point(term_location.block); + let entry_point = self.cx.location_map.entry_point(term_location.block); for p in (entry_point..term_point).rev() { - debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p)); + debug!( + "compute_drop_live_points_for_block: p = {:?}", + self.cx.location_map.to_location(p) + ); if self.defs.contains(p) { debug!("compute_drop_live_points_for_block: def site"); @@ -428,7 +431,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { } let pred_term_loc = self.cx.body.terminator_loc(pred_block); - let pred_term_point = self.cx.elements.point_from_location(pred_term_loc); + let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc); // If the terminator of this predecessor either *assigns* // our value or is a "normal use", then stop. @@ -523,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// points `live_at`. fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet) { debug!("add_use_live_facts_for(value={:?})", value); - Self::make_all_regions_live(self.elements, self.typeck, value, live_at); + Self::make_all_regions_live(self.location_map, self.typeck, value, live_at); } /// Some variable with type `live_ty` is "drop live" at `location` @@ -547,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { dropped_local, dropped_ty, drop_locations, - values::pretty_print_points(self.elements, live_at.iter()), + values::pretty_print_points(self.location_map, live_at.iter()), ); let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ @@ -574,7 +577,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { // All things in the `outlives` array may be touched by // the destructor and must be live at this point. for &kind in &drop_data.dropck_result.kinds { - Self::make_all_regions_live(self.elements, self.typeck, kind, live_at); + Self::make_all_regions_live(self.location_map, self.typeck, kind, live_at); polonius::legacy::emit_drop_facts( self.typeck.tcx(), dropped_local, @@ -586,7 +589,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { } fn make_all_regions_live( - elements: &DenseLocationMap, + location_map: &DenseLocationMap, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeVisitable> + Relate>, live_at: &IntervalSet, @@ -594,7 +597,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { debug!("make_all_regions_live(value={:?})", value); debug!( "make_all_regions_live: live_at={}", - values::pretty_print_points(elements, live_at.iter()), + values::pretty_print_points(location_map, live_at.iter()), ); value.visit_with(&mut for_liveness::FreeRegionsVisitor { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 10fb8a399a267..1ab04bbac5f84 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -103,7 +103,7 @@ mod relate_tys; /// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts /// - `flow_inits` -- results of a maybe-init dataflow analysis /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis -/// - `elements` -- MIR region map +/// - `location_map` -- map between MIR `Location` and `PointIndex` pub(crate) fn type_check<'a, 'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, @@ -114,13 +114,13 @@ pub(crate) fn type_check<'a, 'tcx>( all_facts: &mut Option, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, - elements: Rc, + location_map: Rc, ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), - liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)), + liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&location_map)), outlives_constraints: OutlivesConstraintSet::default(), member_constraints: MemberConstraintSet::default(), type_tests: Vec::default(), @@ -180,7 +180,7 @@ pub(crate) fn type_check<'a, 'tcx>( typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output); typeck.check_signature_annotation(body); - liveness::generate(&mut typeck, body, &elements, flow_inits, move_data); + liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data); let opaque_type_values = opaque_types::take_opaques_and_register_member_constraints(&mut typeck); From 2d236015410269fa6c9e9a8e921883832a9638e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jan 2025 10:40:40 +0100 Subject: [PATCH 103/189] add missing provenance APIs on NonNull --- library/core/src/ptr/non_null.rs | 48 ++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 1058fa42cc1e3..8e78a44bddce6 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -85,6 +85,20 @@ impl !Send for NonNull {} impl !Sync for NonNull {} impl NonNull { + /// Creates a pointer with the given address and no [provenance][crate::ptr#provenance]. + /// + /// For more details, see the equivalent method on a raw pointer, [`ptr::without_provenance_mut`]. + /// + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. + #[unstable(feature = "nonnull_provenance", issue = "135243")] + pub const fn without_provenance(addr: NonZero) -> Self { + // SAFETY: we know `addr` is non-zero. + unsafe { + let ptr = crate::ptr::without_provenance_mut(addr.get()); + NonNull::new_unchecked(ptr) + } + } + /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like @@ -116,6 +130,21 @@ impl NonNull { } } + /// Converts an address back to a mutable pointer, picking up some previously 'exposed' + /// [provenance][crate::ptr#provenance]. + /// + /// For more details, see the equivalent method on a raw pointer, [`ptr::with_exposed_provenance_mut`]. + /// + /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. + #[unstable(feature = "nonnull_provenance", issue = "135243")] + pub fn with_exposed_provenance(addr: NonZero) -> Self { + // SAFETY: we know `addr` is non-zero. + unsafe { + let ptr = crate::ptr::with_exposed_provenance_mut(addr.get()); + NonNull::new_unchecked(ptr) + } + } + /// Returns a shared references to the value. In contrast to [`as_ref`], this does not require /// that the value has to be initialized. /// @@ -282,7 +311,7 @@ impl NonNull { /// Gets the "address" portion of the pointer. /// - /// For more details see the equivalent method on a raw pointer, [`pointer::addr`]. + /// For more details, see the equivalent method on a raw pointer, [`pointer::addr`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] @@ -294,10 +323,23 @@ impl NonNull { unsafe { NonZero::new_unchecked(self.as_ptr().addr()) } } + /// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in + /// [`with_exposed_provenance`][NonNull::with_exposed_provenance] and returns the "address" portion. + /// + /// For more details, see the equivalent method on a raw pointer, [`pointer::expose_provenance`]. + /// + /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. + #[unstable(feature = "nonnull_provenance", issue = "135243")] + pub fn expose_provenance(self) -> NonZero { + // SAFETY: The pointer is guaranteed by the type to be non-null, + // meaning that the address will be non-zero. + unsafe { NonZero::new_unchecked(self.as_ptr().expose_provenance()) } + } + /// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of /// `self`. /// - /// For more details see the equivalent method on a raw pointer, [`pointer::with_addr`]. + /// For more details, see the equivalent method on a raw pointer, [`pointer::with_addr`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] @@ -311,7 +353,7 @@ impl NonNull { /// Creates a new pointer by mapping `self`'s address to a new one, preserving the /// [provenance][crate::ptr#provenance] of `self`. /// - /// For more details see the equivalent method on a raw pointer, [`pointer::map_addr`]. + /// For more details, see the equivalent method on a raw pointer, [`pointer::map_addr`]. /// /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] From 3a1a621115e8965b140bc478c2573a39e8f836a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 8 Jan 2025 11:22:03 +0000 Subject: [PATCH 104/189] rename `LocationTable` to `PoloniusLocationTable` Its original naming hides the fact that it's related to datalog polonius, and bound to be deleted in the near future. It also conflicts with the expected name for the actual NLL location map, and prefixing it with its use will make the differentiation possible. --- compiler/rustc_borrowck/src/consumers.rs | 8 ++--- compiler/rustc_borrowck/src/lib.rs | 9 +++--- compiler/rustc_borrowck/src/nll.rs | 4 +-- .../src/polonius/legacy/accesses.rs | 6 ++-- .../src/polonius/legacy/facts.rs | 32 +++++++++---------- .../src/polonius/legacy/loan_invalidations.rs | 6 ++-- .../src/polonius/legacy/loan_kills.rs | 6 ++-- .../src/polonius/legacy/location.rs | 8 ++--- .../rustc_borrowck/src/polonius/legacy/mod.rs | 6 ++-- compiler/rustc_borrowck/src/type_check/mod.rs | 8 ++--- 10 files changed, 47 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 7e8c48a155136..d242096d30a34 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -11,8 +11,8 @@ pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_a pub use super::place_ext::PlaceExt; pub use super::places_conflict::{PlaceConflictBias, places_conflict}; pub use super::polonius::legacy::{ - AllFacts as PoloniusInput, LocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation, - RustcFacts, + AllFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid, + RichLocation, RustcFacts, }; pub use super::region_infer::RegionInferenceContext; @@ -33,7 +33,7 @@ pub enum ConsumerOptions { /// without significant slowdowns. /// /// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext), - /// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that + /// and additionally retrieve the [`PoloniusLocationTable`] and [`PoloniusInput`] that /// would be given to Polonius. Critically, this does not run Polonius, which /// one may want to avoid due to performance issues on large bodies. PoloniusInputFacts, @@ -71,7 +71,7 @@ pub struct BodyWithBorrowckFacts<'tcx> { /// The table that maps Polonius points to locations in the table. /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] /// or [`ConsumerOptions::PoloniusOutputFacts`]. - pub location_table: Option, + pub location_table: Option, /// Polonius input facts. /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] /// or [`ConsumerOptions::PoloniusOutputFacts`]. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c97c3f3f87035..43979f23fae6d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -56,7 +56,7 @@ use crate::diagnostics::{ use crate::path_utils::*; use crate::place_ext::PlaceExt; use crate::places_conflict::{PlaceConflictBias, places_conflict}; -use crate::polonius::legacy::{LocationTable, PoloniusOutput}; +use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput}; use crate::prefixes::PrefixSet; use crate::region_infer::RegionInferenceContext; use crate::renumber::RegionCtxt; @@ -175,7 +175,7 @@ fn do_mir_borrowck<'tcx>( infcx.register_predefined_opaques_for_next_solver(def); } - let location_table = LocationTable::new(body); + let location_table = PoloniusLocationTable::new(body); let move_data = MoveData::gather_moves(body, tcx, |_| true); let promoted_move_data = promoted @@ -246,7 +246,8 @@ fn do_mir_borrowck<'tcx>( infcx: &infcx, body: promoted_body, move_data: &move_data, - location_table: &location_table, // no need to create a real one for the promoted, it is not used + // no need to create a real location table for the promoted, it is not used + location_table: &location_table, movable_coroutine, fn_self_span_reported: Default::default(), locals_are_invalidated_at_exit, @@ -512,7 +513,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { /// Map from MIR `Location` to `LocationIndex`; created /// when MIR borrowck begins. - location_table: &'a LocationTable, + location_table: &'a PoloniusLocationTable, movable_coroutine: bool, /// This keeps track of whether local variables are free-ed when the function diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8f436dcdb07cc..b4eba62a914de 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -28,7 +28,7 @@ use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors}; use crate::polonius::LocalizedOutlivesConstraintSet; -use crate::polonius::legacy::{AllFacts, AllFactsExt, LocationTable, PoloniusOutput}; +use crate::polonius::legacy::{AllFacts, AllFactsExt, PoloniusLocationTable, PoloniusOutput}; use crate::region_infer::RegionInferenceContext; use crate::type_check::{self, MirTypeckResults}; use crate::universal_regions::UniversalRegions; @@ -80,7 +80,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs index 4a0c8d9b4b461..583290b69bb46 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData}; use tracing::debug; -use super::{AllFacts, LocationIndex, LocationTable}; +use super::{AllFacts, LocationIndex, PoloniusLocationTable}; use crate::def_use::{self, DefUse}; use crate::universal_regions::UniversalRegions; @@ -13,7 +13,7 @@ pub(crate) fn emit_access_facts<'tcx>( tcx: TyCtxt<'tcx>, facts: &mut AllFacts, body: &Body<'tcx>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, move_data: &MoveData<'tcx>, universal_regions: &UniversalRegions<'tcx>, ) { @@ -33,7 +33,7 @@ pub(crate) fn emit_access_facts<'tcx>( struct AccessFactsExtractor<'a, 'tcx> { facts: &'a mut AllFacts, move_data: &'a MoveData<'tcx>, - location_table: &'a LocationTable, + location_table: &'a PoloniusLocationTable, } impl<'tcx> AccessFactsExtractor<'_, 'tcx> { diff --git a/compiler/rustc_borrowck/src/polonius/legacy/facts.rs b/compiler/rustc_borrowck/src/polonius/legacy/facts.rs index 42c4e73321833..804dd60a01f23 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/facts.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/facts.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::Local; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::move_paths::MovePathIndex; -use super::{LocationIndex, LocationTable}; +use super::{LocationIndex, PoloniusLocationTable}; use crate::BorrowIndex; #[derive(Copy, Clone, Debug)] @@ -63,7 +63,7 @@ impl AllFacts { fn write_to_dir( &self, dir: impl AsRef, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, ) -> Result<(), Box> { let dir: &Path = dir.as_ref(); fs::create_dir_all(dir)?; @@ -119,7 +119,7 @@ impl Atom for LocationIndex { } struct FactWriter<'w> { - location_table: &'w LocationTable, + location_table: &'w PoloniusLocationTable, dir: &'w Path, } @@ -141,7 +141,7 @@ trait FactRow { fn write( &self, out: &mut dyn Write, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, ) -> Result<(), Box>; } @@ -149,7 +149,7 @@ impl FactRow for PoloniusRegionVid { fn write( &self, out: &mut dyn Write, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, ) -> Result<(), Box> { write_row(out, location_table, &[self]) } @@ -163,7 +163,7 @@ where fn write( &self, out: &mut dyn Write, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, ) -> Result<(), Box> { write_row(out, location_table, &[&self.0, &self.1]) } @@ -178,7 +178,7 @@ where fn write( &self, out: &mut dyn Write, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, ) -> Result<(), Box> { write_row(out, location_table, &[&self.0, &self.1, &self.2]) } @@ -194,7 +194,7 @@ where fn write( &self, out: &mut dyn Write, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, ) -> Result<(), Box> { write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) } @@ -202,7 +202,7 @@ where fn write_row( out: &mut dyn Write, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, columns: &[&dyn FactCell], ) -> Result<(), Box> { for (index, c) in columns.iter().enumerate() { @@ -213,41 +213,41 @@ fn write_row( } trait FactCell { - fn to_string(&self, location_table: &LocationTable) -> String; + fn to_string(&self, location_table: &PoloniusLocationTable) -> String; } impl FactCell for BorrowIndex { - fn to_string(&self, _location_table: &LocationTable) -> String { + fn to_string(&self, _location_table: &PoloniusLocationTable) -> String { format!("{self:?}") } } impl FactCell for Local { - fn to_string(&self, _location_table: &LocationTable) -> String { + fn to_string(&self, _location_table: &PoloniusLocationTable) -> String { format!("{self:?}") } } impl FactCell for MovePathIndex { - fn to_string(&self, _location_table: &LocationTable) -> String { + fn to_string(&self, _location_table: &PoloniusLocationTable) -> String { format!("{self:?}") } } impl FactCell for PoloniusRegionVid { - fn to_string(&self, _location_table: &LocationTable) -> String { + fn to_string(&self, _location_table: &PoloniusLocationTable) -> String { format!("{self:?}") } } impl FactCell for RegionVid { - fn to_string(&self, _location_table: &LocationTable) -> String { + fn to_string(&self, _location_table: &PoloniusLocationTable) -> String { format!("{self:?}") } } impl FactCell for LocationIndex { - fn to_string(&self, location_table: &LocationTable) -> String { + fn to_string(&self, location_table: &PoloniusLocationTable) -> String { format!("{:?}", location_table.to_rich_location(*self)) } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 3c3b93cdc0d3b..6f2e82ddd0418 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use tracing::debug; -use super::{AllFacts, LocationTable}; +use super::{AllFacts, PoloniusLocationTable}; use crate::borrow_set::BorrowSet; use crate::path_utils::*; use crate::{ @@ -24,7 +24,7 @@ pub(super) fn emit_loan_invalidations<'tcx>( tcx: TyCtxt<'tcx>, facts: &mut AllFacts, body: &Body<'tcx>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, ) { let dominators = body.basic_blocks.dominators(); @@ -37,7 +37,7 @@ struct LoanInvalidationsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, facts: &'a mut AllFacts, body: &'a Body<'tcx>, - location_table: &'a LocationTable, + location_table: &'a PoloniusLocationTable, dominators: &'a Dominators, borrow_set: &'a BorrowSet<'tcx>, } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs index 0148e0b286967..a39dd928edd38 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use tracing::debug; -use super::{AllFacts, LocationTable}; +use super::{AllFacts, PoloniusLocationTable}; use crate::borrow_set::BorrowSet; use crate::places_conflict; @@ -15,7 +15,7 @@ pub(super) fn emit_loan_kills<'tcx>( tcx: TyCtxt<'tcx>, facts: &mut AllFacts, body: &Body<'tcx>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, ) { let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body }; @@ -27,7 +27,7 @@ pub(super) fn emit_loan_kills<'tcx>( struct LoanKillsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, facts: &'a mut AllFacts, - location_table: &'a LocationTable, + location_table: &'a PoloniusLocationTable, borrow_set: &'a BorrowSet<'tcx>, body: &'a Body<'tcx>, } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/location.rs b/compiler/rustc_borrowck/src/polonius/legacy/location.rs index 4cb1202033cb9..5f816bb9bbdc4 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/location.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/location.rs @@ -13,7 +13,7 @@ use tracing::debug; /// granularity through outlives relations; however, the rich location /// table serves another purpose: it compresses locations from /// multiple words into a single u32. -pub struct LocationTable { +pub struct PoloniusLocationTable { num_points: usize, statements_before_block: IndexVec, } @@ -30,7 +30,7 @@ pub enum RichLocation { Mid(Location), } -impl LocationTable { +impl PoloniusLocationTable { pub(crate) fn new(body: &Body<'_>) -> Self { let mut num_points = 0; let statements_before_block = body @@ -43,8 +43,8 @@ impl LocationTable { }) .collect(); - debug!("LocationTable(statements_before_block={:#?})", statements_before_block); - debug!("LocationTable: num_points={:#?}", num_points); + debug!("PoloniusLocationTable(statements_before_block={:#?})", statements_before_block); + debug!("PoloniusLocationTable: num_points={:#?}", num_points); Self { num_points, statements_before_block } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs index 45bdbd1e9997e..b070d8484624b 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs @@ -38,7 +38,7 @@ pub use self::facts::*; pub(crate) fn emit_facts<'tcx>( all_facts: &mut Option, tcx: TyCtxt<'tcx>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, move_data: &MoveData<'tcx>, @@ -69,7 +69,7 @@ pub(crate) fn emit_facts<'tcx>( fn emit_move_facts( facts: &mut AllFacts, body: &Body<'_>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, move_data: &MoveData<'_>, ) { facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); @@ -202,7 +202,7 @@ pub(crate) fn emit_drop_facts<'tcx>( /// closure. fn emit_outlives_facts<'tcx>( facts: &mut AllFacts, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, constraints: &MirTypeckRegionConstraints<'tcx>, ) { facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 1ab04bbac5f84..e85022ea91958 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -49,7 +49,7 @@ use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet}; use crate::diagnostics::UniverseInfo; use crate::member_constraints::MemberConstraintSet; use crate::polonius::PoloniusContext; -use crate::polonius::legacy::{AllFacts, LocationTable}; +use crate::polonius::legacy::{AllFacts, PoloniusLocationTable}; use crate::region_infer::TypeTest; use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::renumber::RegionCtxt; @@ -98,7 +98,7 @@ mod relate_tys; /// - `body` -- MIR body to type-check /// - `promoted` -- map of promoted constants within `body` /// - `universal_regions` -- the universal regions from `body`s function signature -/// - `location_table` -- MIR location map of `body` +/// - `location_table` -- for datalog polonius, the map between `Location`s and `RichLocation`s /// - `borrow_set` -- information about borrows occurring in `body` /// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts /// - `flow_inits` -- results of a maybe-init dataflow analysis @@ -109,7 +109,7 @@ pub(crate) fn type_check<'a, 'tcx>( body: &Body<'tcx>, promoted: &IndexSlice>, universal_regions: UniversalRegions<'tcx>, - location_table: &LocationTable, + location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, @@ -560,7 +560,7 @@ struct TypeChecker<'a, 'tcx> { implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, - location_table: &'a LocationTable, + location_table: &'a PoloniusLocationTable, all_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, From 36ea00c20d24f3eafdaa5b79c2c16f28c2b4a76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 8 Jan 2025 13:23:54 +0000 Subject: [PATCH 105/189] rename `AllFacts` to `PoloniusFacts` This is another strangely named struct (and associated fields) that is hard to see was related to datalog polonius. --- compiler/rustc_borrowck/src/consumers.rs | 2 +- compiler/rustc_borrowck/src/nll.rs | 22 ++++++++++--------- .../src/polonius/legacy/accesses.rs | 6 ++--- .../src/polonius/legacy/facts.rs | 10 ++++----- .../src/polonius/legacy/loan_invalidations.rs | 6 ++--- .../src/polonius/legacy/loan_kills.rs | 6 ++--- .../rustc_borrowck/src/polonius/legacy/mod.rs | 14 ++++++------ .../src/type_check/liveness/trace.rs | 6 ++--- compiler/rustc_borrowck/src/type_check/mod.rs | 20 ++++++++--------- 9 files changed, 47 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index d242096d30a34..5a89f7c351cf6 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -11,7 +11,7 @@ pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_a pub use super::place_ext::PlaceExt; pub use super::places_conflict::{PlaceConflictBias, places_conflict}; pub use super::polonius::legacy::{ - AllFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid, + PoloniusFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation, RustcFacts, }; pub use super::region_infer::RegionInferenceContext; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index b4eba62a914de..aa0bfd7214729 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -28,7 +28,9 @@ use crate::borrow_set::BorrowSet; use crate::consumers::ConsumerOptions; use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors}; use crate::polonius::LocalizedOutlivesConstraintSet; -use crate::polonius::legacy::{AllFacts, AllFactsExt, PoloniusLocationTable, PoloniusOutput}; +use crate::polonius::legacy::{ + PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput, +}; use crate::region_infer::RegionInferenceContext; use crate::type_check::{self, MirTypeckResults}; use crate::universal_regions::UniversalRegions; @@ -39,7 +41,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber}; pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, pub opaque_type_values: FxIndexMap>, - pub polonius_input: Option>, + pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, pub nll_errors: RegionErrors<'tcx>, @@ -91,8 +93,8 @@ pub(crate) fn compute_regions<'a, 'tcx>( || is_polonius_legacy_enabled; let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default() || is_polonius_legacy_enabled; - let mut all_facts = - (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); + let mut polonius_facts = + (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default()); let location_map = Rc::new(DenseLocationMap::new(body)); @@ -109,7 +111,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( universal_regions, location_table, borrow_set, - &mut all_facts, + &mut polonius_facts, flow_inits, move_data, Rc::clone(&location_map), @@ -122,7 +124,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( // If requested, emit legacy polonius facts. polonius::legacy::emit_facts( - &mut all_facts, + &mut polonius_facts, infcx.tcx, location_table, body, @@ -147,13 +149,13 @@ pub(crate) fn compute_regions<'a, 'tcx>( }); // If requested: dump NLL facts, and run legacy polonius analysis. - let polonius_output = all_facts.as_ref().and_then(|all_facts| { + let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| { if infcx.tcx.sess.opts.unstable_opts.nll_facts { let def_id = body.source.def_id(); let def_path = infcx.tcx.def_path(def_id); let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir) .join(def_path.to_filename_friendly_no_crate()); - all_facts.write_to_dir(dir_path, location_table).unwrap(); + polonius_facts.write_to_dir(dir_path, location_table).unwrap(); } if polonius_output { @@ -162,7 +164,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( let algorithm = Algorithm::from_str(&algorithm).unwrap(); debug!("compute_regions: using polonius algorithm {:?}", algorithm); let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); - Some(Box::new(Output::compute(all_facts, algorithm, false))) + Some(Box::new(Output::compute(polonius_facts, algorithm, false))) } else { None } @@ -182,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( NllOutput { regioncx, opaque_type_values: remapped_opaque_tys, - polonius_input: all_facts.map(Box::new), + polonius_input: polonius_facts.map(Box::new), polonius_output, opt_closure_req: closure_region_requirements, nll_errors, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs index 583290b69bb46..edd7ca578b727 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -4,14 +4,14 @@ use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData}; use tracing::debug; -use super::{AllFacts, LocationIndex, PoloniusLocationTable}; +use super::{LocationIndex, PoloniusFacts, PoloniusLocationTable}; use crate::def_use::{self, DefUse}; use crate::universal_regions::UniversalRegions; /// Emit polonius facts for variable defs, uses, drops, and path accesses. pub(crate) fn emit_access_facts<'tcx>( tcx: TyCtxt<'tcx>, - facts: &mut AllFacts, + facts: &mut PoloniusFacts, body: &Body<'tcx>, location_table: &PoloniusLocationTable, move_data: &MoveData<'tcx>, @@ -31,7 +31,7 @@ pub(crate) fn emit_access_facts<'tcx>( /// MIR visitor extracting point-wise facts about accesses. struct AccessFactsExtractor<'a, 'tcx> { - facts: &'a mut AllFacts, + facts: &'a mut PoloniusFacts, move_data: &'a MoveData<'tcx>, location_table: &'a PoloniusLocationTable, } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/facts.rs b/compiler/rustc_borrowck/src/polonius/legacy/facts.rs index 804dd60a01f23..64389b11a651a 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/facts.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/facts.rs @@ -4,7 +4,7 @@ use std::fs::{self, File}; use std::io::Write; use std::path::Path; -use polonius_engine::{AllFacts as PoloniusFacts, Atom, Output}; +use polonius_engine::{AllFacts, Atom, Output}; use rustc_macros::extension; use rustc_middle::mir::Local; use rustc_middle::ty::{RegionVid, TyCtxt}; @@ -49,11 +49,11 @@ impl polonius_engine::FactTypes for RustcFacts { type Path = MovePathIndex; } -pub type AllFacts = PoloniusFacts; +pub type PoloniusFacts = AllFacts; -#[extension(pub(crate) trait AllFactsExt)] -impl AllFacts { - /// Returns `true` if there is a need to gather `AllFacts` given the +#[extension(pub(crate) trait PoloniusFactsExt)] +impl PoloniusFacts { + /// Returns `true` if there is a need to gather `PoloniusFacts` given the /// current `-Z` flags. fn enabled(tcx: TyCtxt<'_>) -> bool { tcx.sess.opts.unstable_opts.nll_facts diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 6f2e82ddd0418..0ad91ae51a3a0 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use tracing::debug; -use super::{AllFacts, PoloniusLocationTable}; +use super::{PoloniusFacts, PoloniusLocationTable}; use crate::borrow_set::BorrowSet; use crate::path_utils::*; use crate::{ @@ -22,7 +22,7 @@ use crate::{ /// Emit `loan_invalidated_at` facts. pub(super) fn emit_loan_invalidations<'tcx>( tcx: TyCtxt<'tcx>, - facts: &mut AllFacts, + facts: &mut PoloniusFacts, body: &Body<'tcx>, location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, @@ -35,7 +35,7 @@ pub(super) fn emit_loan_invalidations<'tcx>( struct LoanInvalidationsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - facts: &'a mut AllFacts, + facts: &'a mut PoloniusFacts, body: &'a Body<'tcx>, location_table: &'a PoloniusLocationTable, dominators: &'a Dominators, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs index a39dd928edd38..098c922bf7b91 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs @@ -6,14 +6,14 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use tracing::debug; -use super::{AllFacts, PoloniusLocationTable}; +use super::{PoloniusFacts, PoloniusLocationTable}; use crate::borrow_set::BorrowSet; use crate::places_conflict; /// Emit `loan_killed_at` and `cfg_edge` facts at the same time. pub(super) fn emit_loan_kills<'tcx>( tcx: TyCtxt<'tcx>, - facts: &mut AllFacts, + facts: &mut PoloniusFacts, body: &Body<'tcx>, location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, @@ -26,7 +26,7 @@ pub(super) fn emit_loan_kills<'tcx>( struct LoanKillsGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, - facts: &'a mut AllFacts, + facts: &'a mut PoloniusFacts, location_table: &'a PoloniusLocationTable, borrow_set: &'a BorrowSet<'tcx>, body: &'a Body<'tcx>, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs index b070d8484624b..95820c07a02f8 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs @@ -36,7 +36,7 @@ pub use self::facts::*; /// /// The rest of the facts are emitted during typeck and liveness. pub(crate) fn emit_facts<'tcx>( - all_facts: &mut Option, + facts: &mut Option, tcx: TyCtxt<'tcx>, location_table: &PoloniusLocationTable, body: &Body<'tcx>, @@ -45,7 +45,7 @@ pub(crate) fn emit_facts<'tcx>( universal_region_relations: &UniversalRegionRelations<'tcx>, constraints: &MirTypeckRegionConstraints<'tcx>, ) { - let Some(facts) = all_facts else { + let Some(facts) = facts else { // We don't do anything if there are no facts to fill. return; }; @@ -67,7 +67,7 @@ pub(crate) fn emit_facts<'tcx>( /// Emit facts needed for move/init analysis: moves and assignments. fn emit_move_facts( - facts: &mut AllFacts, + facts: &mut PoloniusFacts, body: &Body<'_>, location_table: &PoloniusLocationTable, move_data: &MoveData<'_>, @@ -139,7 +139,7 @@ fn emit_move_facts( /// Emit universal regions facts, and their relations. fn emit_universal_region_facts( - facts: &mut AllFacts, + facts: &mut PoloniusFacts, borrow_set: &BorrowSet<'_>, universal_region_relations: &UniversalRegionRelations<'_>, ) { @@ -187,10 +187,10 @@ pub(crate) fn emit_drop_facts<'tcx>( local: Local, kind: &GenericArg<'tcx>, universal_regions: &UniversalRegions<'tcx>, - all_facts: &mut Option, + facts: &mut Option, ) { debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind); - let Some(facts) = all_facts.as_mut() else { return }; + let Some(facts) = facts.as_mut() else { return }; let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); tcx.for_each_free_region(kind, |drop_live_region| { let region_vid = universal_regions.to_region_vid(drop_live_region); @@ -201,7 +201,7 @@ pub(crate) fn emit_drop_facts<'tcx>( /// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive /// closure. fn emit_outlives_facts<'tcx>( - facts: &mut AllFacts, + facts: &mut PoloniusFacts, location_table: &PoloniusLocationTable, constraints: &MirTypeckRegionConstraints<'tcx>, ) { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 2e09821b358a8..7fce49fd16bb9 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -213,14 +213,14 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) { // This collect is more necessary than immediately apparent // because these facts go into `add_drop_live_facts_for()`, - // which also writes to `all_facts`, and so this is genuinely + // which also writes to `polonius_facts`, and so this is genuinely // a simultaneous overlapping mutable borrow. // FIXME for future hackers: investigate whether this is // actually necessary; these facts come from Polonius // and probably maybe plausibly does not need to go back in. // It may be necessary to just pick out the parts of // `add_drop_live_facts_for()` that make sense. - let Some(facts) = self.cx.typeck.all_facts.as_ref() else { return }; + let Some(facts) = self.cx.typeck.polonius_facts.as_ref() else { return }; let facts_to_add: Vec<_> = { let relevant_live_locals: FxIndexSet<_> = relevant_live_locals.iter().copied().collect(); @@ -583,7 +583,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { dropped_local, &kind, self.typeck.universal_regions, - self.typeck.all_facts, + self.typeck.polonius_facts, ); } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e85022ea91958..97e4b7433c0e7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -49,7 +49,7 @@ use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet}; use crate::diagnostics::UniverseInfo; use crate::member_constraints::MemberConstraintSet; use crate::polonius::PoloniusContext; -use crate::polonius::legacy::{AllFacts, PoloniusLocationTable}; +use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable}; use crate::region_infer::TypeTest; use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::renumber::RegionCtxt; @@ -100,7 +100,7 @@ mod relate_tys; /// - `universal_regions` -- the universal regions from `body`s function signature /// - `location_table` -- for datalog polonius, the map between `Location`s and `RichLocation`s /// - `borrow_set` -- information about borrows occurring in `body` -/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts +/// - `polonius_facts` -- when using Polonius, this is the generated set of Polonius facts /// - `flow_inits` -- results of a maybe-init dataflow analysis /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `location_map` -- map between MIR `Location` and `PointIndex` @@ -111,7 +111,7 @@ pub(crate) fn type_check<'a, 'tcx>( universal_regions: UniversalRegions<'tcx>, location_table: &PoloniusLocationTable, borrow_set: &BorrowSet<'tcx>, - all_facts: &mut Option, + polonius_facts: &mut Option, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, location_map: Rc, @@ -165,7 +165,7 @@ pub(crate) fn type_check<'a, 'tcx>( reported_errors: Default::default(), universal_regions: &universal_region_relations.universal_regions, location_table, - all_facts, + polonius_facts, borrow_set, constraints: &mut constraints, polonius_context: &mut polonius_context, @@ -495,14 +495,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // Use new sets of constraints and closure bounds so that we can // modify their locations. - let all_facts = &mut None; + let polonius_facts = &mut None; let mut constraints = Default::default(); let mut liveness_constraints = LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); // Don't try to add borrow_region facts for the promoted MIR let mut swap_constraints = |this: &mut Self| { - mem::swap(this.typeck.all_facts, all_facts); + mem::swap(this.typeck.polonius_facts, polonius_facts); mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints); mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints); }; @@ -561,7 +561,7 @@ struct TypeChecker<'a, 'tcx> { reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a PoloniusLocationTable, - all_facts: &'a mut Option, + polonius_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, /// When using `-Zpolonius=next`, the helper data used to create polonius constraints. @@ -2327,18 +2327,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { borrowed_place: &Place<'tcx>, ) { // These constraints are only meaningful during borrowck: - let Self { borrow_set, location_table, all_facts, constraints, .. } = self; + let Self { borrow_set, location_table, polonius_facts, constraints, .. } = self; // In Polonius mode, we also push a `loan_issued_at` fact // linking the loan to the region (in some cases, though, // there is no loan associated with this borrow expression -- // that occurs when we are borrowing an unsafe place, for // example). - if let Some(all_facts) = all_facts { + if let Some(polonius_facts) = polonius_facts { let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); if let Some(borrow_index) = borrow_set.get_index_of(&location) { let region_vid = borrow_region.as_var(); - all_facts.loan_issued_at.push(( + polonius_facts.loan_issued_at.push(( region_vid.into(), borrow_index, location_table.mid_index(location), From 2ab8b0b4f9a4c42c6d289c6373752a6527f4d90d Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 14:38:34 +0100 Subject: [PATCH 106/189] fix release notes link --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index fe557a08a9dc0..7c2c2406e9062 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -37,7 +37,7 @@ Libraries - [Move `::copysign`, `::abs`, `::signum` to `core`](https://github.com/rust-lang/rust/pull/131304) - [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377) - [Implement `FromStr` for `CString` and `TryFrom` for `String`](https://github.com/rust-lang/rust/pull/130608) -- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/130635) +- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/123723) From e98a41ea0781785a893e4e494e6a6cf90350492a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 14:43:50 +0100 Subject: [PATCH 107/189] Revert "fix missing rustfmt for apple darwin" This reverts commit 2316749ca954030afed6145342808a8c1ae29fac. --- src/bootstrap/src/core/build_steps/dist.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 8bfa9cc94b341..bcf12d6d036b6 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1592,15 +1592,9 @@ impl Step for Extended { prepare("cargo"); prepare("rust-std"); prepare("rust-analysis"); - - for tool in &[ - "clippy", - "rustfmt", - "rust-analyzer", - "rust-docs", - "miri", - "rustc-codegen-cranelift", - ] { + prepare("clippy"); + prepare("rust-analyzer"); + for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] { if built_tools.contains(tool) { prepare(tool); } From ee2b8eee38df5f4b4f7ffd53460804cb8f57ed51 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 14:44:01 +0100 Subject: [PATCH 108/189] Revert "fix missing rustfmt and clippy for msi" This reverts commit f5577a8174685aca342b9189e625648f25a23a20. --- src/bootstrap/src/core/build_steps/dist.rs | 31 +--------------- src/etc/installer/msi/rust.wxs | 41 +--------------------- 2 files changed, 2 insertions(+), 70 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index bcf12d6d036b6..aa664998f979e 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1634,8 +1634,6 @@ impl Step for Extended { "rust-analyzer-preview".to_string() } else if name == "clippy" { "clippy-preview".to_string() - } else if name == "rustfmt" { - "rustfmt-preview".to_string() } else if name == "miri" { "miri-preview".to_string() } else if name == "rustc-codegen-cranelift" { @@ -1655,7 +1653,7 @@ impl Step for Extended { prepare("cargo"); prepare("rust-analysis"); prepare("rust-std"); - for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] { + for tool in &["clippy", "rust-analyzer", "rust-docs", "miri"] { if built_tools.contains(tool) { prepare(tool); } @@ -1773,24 +1771,6 @@ impl Step for Extended { .arg(etc.join("msi/remove-duplicates.xsl")) .run(builder); } - if built_tools.contains("rustfmt") { - command(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rustfmt") - .args(heat_flags) - .arg("-cg") - .arg("RustFmtGroup") - .arg("-dr") - .arg("RustFmt") - .arg("-var") - .arg("var.RustFmtDir") - .arg("-out") - .arg(exe.join("RustFmtGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")) - .run(builder); - } if built_tools.contains("miri") { command(&heat) .current_dir(&exe) @@ -1862,9 +1842,6 @@ impl Step for Extended { if built_tools.contains("clippy") { cmd.arg("-dClippyDir=clippy"); } - if built_tools.contains("rustfmt") { - cmd.arg("-dRustFmtDir=rustfmt"); - } if built_tools.contains("rust-docs") { cmd.arg("-dDocsDir=rust-docs"); } @@ -1891,9 +1868,6 @@ impl Step for Extended { if built_tools.contains("clippy") { candle("ClippyGroup.wxs".as_ref()); } - if built_tools.contains("rustfmt") { - candle("RustFmtGroup.wxs".as_ref()); - } if built_tools.contains("miri") { candle("MiriGroup.wxs".as_ref()); } @@ -1932,9 +1906,6 @@ impl Step for Extended { if built_tools.contains("clippy") { cmd.arg("ClippyGroup.wixobj"); } - if built_tools.contains("rustfmt") { - cmd.arg("RustFmtGroup.wixobj"); - } if built_tools.contains("miri") { cmd.arg("MiriGroup.wixobj"); } diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index 2d155bf0b1019..f29e1e4d27a27 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -172,11 +172,6 @@ - - - - - @@ -284,41 +279,7 @@ - - - - - - - - - - - - - - - + From 61bda87b0d1d39e53b3a929b35dbbc8688875af2 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 8 Jan 2025 14:19:04 +0000 Subject: [PATCH 109/189] Move `mod cargo` below the import statements Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 30e42a5bfb78d..2e89fb231e320 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1,5 +1,3 @@ -mod cargo; - use std::any::{Any, type_name}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; @@ -25,6 +23,8 @@ use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t}; use crate::{Build, Crate}; +mod cargo; + #[cfg(test)] mod tests; From 045271ccccd6c485f65ed94aeef3357a512e22fb Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Thu, 5 Dec 2024 02:58:59 +0800 Subject: [PATCH 110/189] run borrowck tests on BIDs and emit tail-expr-drop-order lints for potential violations --- compiler/rustc_borrowck/messages.ftl | 3 + compiler/rustc_borrowck/src/lib.rs | 79 +++++++++++++++---- .../rustc_borrowck/src/session_diagnostics.rs | 7 ++ compiler/rustc_mir_build/src/builder/scope.rs | 6 +- .../lint-tail-expr-drop-order-borrowck.rs | 37 +++++++++ .../lint-tail-expr-drop-order-borrowck.stderr | 40 ++++++++++ 6 files changed, 155 insertions(+), 17 deletions(-) create mode 100644 tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs create mode 100644 tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index ee4b2f95cb151..c1d5af59b1b5b 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -213,6 +213,9 @@ borrowck_suggest_create_fresh_reborrow = borrowck_suggest_iterate_over_slice = consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop +borrowck_tail_expr_drop_order = a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error + .label = consider using a `let` binding to create a longer lived value; or replacing the `{"{"} .. {"}"}` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe {"{"} .. {"}"}` + borrowck_ty_no_impl_copy = {$is_partial_move -> [true] partial move diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 88d0933d8ce8b..8d8a3c67c7b71 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -16,6 +16,7 @@ #![warn(unreachable_pub)] // tidy-alphabetical-end +use std::borrow::Cow; use std::cell::RefCell; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; @@ -24,6 +25,7 @@ use rustc_abi::FieldIdx; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir as hir; +use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_index::{IndexSlice, IndexVec}; @@ -43,7 +45,7 @@ use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; -use rustc_session::lint::builtin::UNUSED_MUT; +use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; use rustc_span::{Span, Symbol}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -636,9 +638,11 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< | StatementKind::Coverage(..) // These do not actually affect borrowck | StatementKind::ConstEvalCounter - // This do not affect borrowck - | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::StorageLive(..) => {} + // This does not affect borrowck + StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => { + self.check_backward_incompatible_drop(location, (**place, span), state); + } StatementKind::StorageDead(local) => { self.access_place( location, @@ -1007,6 +1011,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } + fn maybe_polonius_borrows_in_scope<'s>( + &self, + location: Location, + state: &'s BorrowckDomain, + ) -> Cow<'s, BitSet> { + if let Some(polonius) = &self.polonius_output { + let location = self.location_table.start_index(location); + let mut polonius_output = BitSet::new_empty(self.borrow_set.len()); + for &idx in polonius.errors_at(location) { + polonius_output.insert(idx); + } + Cow::Owned(polonius_output) + } else { + Cow::Borrowed(&state.borrows) + } + } + #[instrument(level = "debug", skip(self, state))] fn check_access_for_conflict( &mut self, @@ -1019,17 +1040,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let mut error_reported = false; // Use polonius output if it has been enabled. - let mut polonius_output; - let borrows_in_scope = if let Some(polonius) = &self.polonius_output { - let location = self.location_table.start_index(location); - polonius_output = BitSet::new_empty(self.borrow_set.len()); - for &idx in polonius.errors_at(location) { - polonius_output.insert(idx); - } - &polonius_output - } else { - &state.borrows - }; + let borrows_in_scope = self.maybe_polonius_borrows_in_scope(location, state); each_borrow_involving_path( self, @@ -1149,6 +1160,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { error_reported } + /// Through #123739, backward incompatible drops (BIDs) are introduced. + /// We would like to emit lints whether borrow checking fails at these future drop locations. + #[instrument(level = "debug", skip(self, state))] + fn check_backward_incompatible_drop( + &mut self, + location: Location, + place_span: (Place<'tcx>, Span), + state: &BorrowckDomain, + ) { + let sd = AccessDepth::Drop; + + // Use polonius output if it has been enabled. + let borrows_in_scope = self.maybe_polonius_borrows_in_scope(location, state); + + // This is a very simplified version of `Self::check_access_for_conflict`. + // We are here checking on BIDs and specifically still-live borrows of data involving the BIDs. + each_borrow_involving_path( + self, + self.infcx.tcx, + self.body, + (sd, place_span.0), + self.borrow_set, + |borrow_index| borrows_in_scope.contains(borrow_index), + |this, _borrow_index, borrow| { + if matches!(borrow.kind, BorrowKind::Fake(_)) { + return Control::Continue; + } + let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span(); + this.infcx.tcx.emit_node_span_lint( + TAIL_EXPR_DROP_ORDER, + CRATE_HIR_ID, + place_span.1, + session_diagnostics::TailExprDropOrder { borrowed }, + ); + // We may stop at the first case + Control::Break + }, + ); + } + fn mutate_place( &mut self, location: Location, diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 627444a4ce5b8..4be5d0dbf4284 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -480,3 +480,10 @@ pub(crate) struct SimdIntrinsicArgConst { pub arg: usize, pub intrinsic: String, } + +#[derive(LintDiagnostic)] +#[diag(borrowck_tail_expr_drop_order)] +pub(crate) struct TailExprDropOrder { + #[label] + pub borrowed: Span, +} diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 35c98037827af..20441530a4790 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1131,15 +1131,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Schedule emission of a backwards incompatible drop lint hint. /// Applicable only to temporary values for now. + #[instrument(level = "debug", skip(self))] pub(crate) fn schedule_backwards_incompatible_drop( &mut self, span: Span, region_scope: region::Scope, local: Local, ) { - if !self.local_decls[local].ty.has_significant_drop(self.tcx, self.typing_env()) { - return; - } + // Note that we are *not* gating BIDs here on whether they have significant destructor. + // We need to know all of them so that we can capture potential borrow-checking errors. for scope in self.scopes.scopes.iter_mut().rev() { // Since we are inserting linting MIR statement, we have to invalidate the caches scope.invalidate_cache(); diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs new file mode 100644 index 0000000000000..1bd5655d7fe1d --- /dev/null +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs @@ -0,0 +1,37 @@ +// Edition 2024 lint for change in drop order at tail expression +// This lint is to capture potential borrow-checking errors +// due to implementation of RFC 3606 +//@ edition: 2021 + +#![deny(tail_expr_drop_order)] //~ NOTE: the lint level is defined here + +fn should_lint_with_potential_borrowck_err() { + let _ = { String::new().as_str() }.len(); + //~^ ERROR: a temporary value will be dropped here + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: consider using a `let` binding + //~| NOTE: for more information, see +} + +fn should_lint_with_unsafe_block() { + fn f(_: usize) {} + f(unsafe { String::new().as_str() }.len()); + //~^ ERROR: a temporary value will be dropped here + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: consider using a `let` binding + //~| NOTE: for more information, see +} + +#[rustfmt::skip] +fn should_lint_with_big_block() { + fn f(_: T) {} + f({ + &mut || 0 + //~^ ERROR: a temporary value will be dropped here + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: consider using a `let` binding + //~| NOTE: for more information, see + }) +} + +fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr new file mode 100644 index 0000000000000..98ef0547c9075 --- /dev/null +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr @@ -0,0 +1,40 @@ +error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:9:36 + | +LL | let _ = { String::new().as_str() }.len(); + | ------------- ^ + | | + | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: the lint level is defined here + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:6:9 + | +LL | #![deny(tail_expr_drop_order)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:18:37 + | +LL | f(unsafe { String::new().as_str() }.len()); + | ------------- ^ + | | + | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see + +error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:29:17 + | +LL | &mut || 0 + | --------^ + | | + | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see + +error: aborting due to 3 previous errors + From 34edb21f0bb34916410eb92b108d84075e4abd7e Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Fri, 20 Dec 2024 01:21:51 +0800 Subject: [PATCH 111/189] apply suggestions on fn name --- compiler/rustc_borrowck/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8d8a3c67c7b71..7eb714009d10a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1011,12 +1011,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn maybe_polonius_borrows_in_scope<'s>( + fn borrows_in_scope<'s>( &self, location: Location, state: &'s BorrowckDomain, ) -> Cow<'s, BitSet> { if let Some(polonius) = &self.polonius_output { + // Use polonius output if it has been enabled. let location = self.location_table.start_index(location); let mut polonius_output = BitSet::new_empty(self.borrow_set.len()); for &idx in polonius.errors_at(location) { @@ -1039,8 +1040,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ) -> bool { let mut error_reported = false; - // Use polonius output if it has been enabled. - let borrows_in_scope = self.maybe_polonius_borrows_in_scope(location, state); + let borrows_in_scope = self.borrows_in_scope(location, state); each_borrow_involving_path( self, @@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let sd = AccessDepth::Drop; // Use polonius output if it has been enabled. - let borrows_in_scope = self.maybe_polonius_borrows_in_scope(location, state); + let borrows_in_scope = self.borrows_in_scope(location, state); // This is a very simplified version of `Self::check_access_for_conflict`. // We are here checking on BIDs and specifically still-live borrows of data involving the BIDs. From 13c7122df869f6b29799ea96599cce1fc5880376 Mon Sep 17 00:00:00 2001 From: wieDasDing <6884440+dingxiangfei2009@users.noreply.github.com> Date: Fri, 20 Dec 2024 02:08:36 +0800 Subject: [PATCH 112/189] remove an extraneous comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémy Rakic --- compiler/rustc_borrowck/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 7eb714009d10a..df3368bdd30ae 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1171,7 +1171,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ) { let sd = AccessDepth::Drop; - // Use polonius output if it has been enabled. let borrows_in_scope = self.borrows_in_scope(location, state); // This is a very simplified version of `Self::check_access_for_conflict`. From 197f6d8081451c5ad394601dbdd8509bbb92f446 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 5 Jan 2025 18:07:16 +0000 Subject: [PATCH 113/189] Don't create cycles by normalizing opaques defined in the body we're checking --- .../src/lint_tail_expr_drop_order.rs | 7 ++++- tests/ui/drop/lint-tail-expr-drop-order.rs | 1 - .../ui/drop/lint-tail-expr-drop-order.stderr | 27 +++++++------------ ...expr_drop_order-on-coroutine-unwind.stderr | 4 +++ ..._expr_drop_order-on-recursive-boxed-fut.rs | 13 +++++++++ 5 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 tests/ui/drop/tail_expr_drop_order-on-recursive-boxed-fut.rs diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index e5a183bc75ce5..6590702118c7f 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -351,6 +351,11 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< { return; } + + // FIXME(typing_env): This should be able to reveal the opaques local to the + // body using the typeck results. + let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); + // ## About BIDs in blocks ## // Track the set of blocks that contain a backwards-incompatible drop (BID) // and, for each block, the vector of locations. @@ -358,7 +363,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< // We group them per-block because they tend to scheduled in the same drop ladder block. let mut bid_per_block = IndexMap::default(); let mut bid_places = UnordSet::new(); - let typing_env = ty::TypingEnv::post_analysis(tcx, def_id); + let mut ty_dropped_components = UnordMap::default(); for (block, data) in body.basic_blocks.iter_enumerated() { for (statement_index, stmt) in data.statements.iter().enumerate() { diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs index b2a5db0d87133..55a2d1d3b7543 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order.rs @@ -17,7 +17,6 @@ impl Drop for LoudDropper { //~| NOTE: `#1` invokes this custom destructor //~| NOTE: `x` invokes this custom destructor //~| NOTE: `#1` invokes this custom destructor - //~| NOTE: `future` invokes this custom destructor //~| NOTE: `_x` invokes this custom destructor //~| NOTE: `#1` invokes this custom destructor fn drop(&mut self) { diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index 92afae5af6766..6ff9b7c12681d 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -1,5 +1,5 @@ error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:41:15 + --> $DIR/lint-tail-expr-drop-order.rs:40:15 | LL | let x = LoudDropper; | - @@ -40,7 +40,7 @@ LL | #![deny(tail_expr_drop_order)] | ^^^^^^^^^^^^^^^^^^^^ error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:66:19 + --> $DIR/lint-tail-expr-drop-order.rs:65:19 | LL | let x = LoudDropper; | - @@ -76,7 +76,7 @@ LL | | } = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:93:7 + --> $DIR/lint-tail-expr-drop-order.rs:92:7 | LL | let x = LoudDropper; | - @@ -112,7 +112,7 @@ LL | | } = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:146:5 + --> $DIR/lint-tail-expr-drop-order.rs:145:5 | LL | let future = f(); | ------ @@ -136,19 +136,12 @@ note: `#1` invokes this custom destructor | LL | / impl Drop for LoudDropper { ... | -LL | | } - | |_^ -note: `future` invokes this custom destructor - --> $DIR/lint-tail-expr-drop-order.rs:10:1 - | -LL | / impl Drop for LoudDropper { -... | LL | | } | |_^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:163:14 + --> $DIR/lint-tail-expr-drop-order.rs:162:14 | LL | let x = T::default(); | - @@ -170,7 +163,7 @@ LL | } = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:177:5 + --> $DIR/lint-tail-expr-drop-order.rs:176:5 | LL | let x: Result = Ok(LoudDropper); | - @@ -206,7 +199,7 @@ LL | | } = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:221:5 + --> $DIR/lint-tail-expr-drop-order.rs:220:5 | LL | let x = LoudDropper2; | - @@ -226,7 +219,7 @@ LL | } = warning: this changes meaning in Rust 2024 = note: for more information, see note: `#1` invokes this custom destructor - --> $DIR/lint-tail-expr-drop-order.rs:194:5 + --> $DIR/lint-tail-expr-drop-order.rs:193:5 | LL | / impl Drop for LoudDropper3 { LL | | @@ -236,7 +229,7 @@ LL | | } LL | | } | |_____^ note: `x` invokes this custom destructor - --> $DIR/lint-tail-expr-drop-order.rs:206:5 + --> $DIR/lint-tail-expr-drop-order.rs:205:5 | LL | / impl Drop for LoudDropper2 { LL | | @@ -248,7 +241,7 @@ LL | | } = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 - --> $DIR/lint-tail-expr-drop-order.rs:234:13 + --> $DIR/lint-tail-expr-drop-order.rs:233:13 | LL | LoudDropper.get() | ^^^^^^^^^^^ diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr index d98100bc1b04c..b0f971dd5cec6 100644 --- a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr +++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr @@ -4,10 +4,14 @@ error: relative drop order changing in Rust 2024 LL | match func().await { | ^^^^^^^----- | | | + | | this value will be stored in a temporary; let us call it `#3` + | | up until Edition 2021 `#3` is dropped last but will be dropped earlier in Edition 2024 | | this value will be stored in a temporary; let us call it `#1` | | `#1` will be dropped later as of Edition 2024 | this value will be stored in a temporary; let us call it `#2` | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 + | `__awaitee` calls a custom destructor + | `__awaitee` will be dropped later as of Edition 2024 ... LL | Err(e) => {} | - diff --git a/tests/ui/drop/tail_expr_drop_order-on-recursive-boxed-fut.rs b/tests/ui/drop/tail_expr_drop_order-on-recursive-boxed-fut.rs new file mode 100644 index 0000000000000..4a72f224d9436 --- /dev/null +++ b/tests/ui/drop/tail_expr_drop_order-on-recursive-boxed-fut.rs @@ -0,0 +1,13 @@ +//@ edition: 2021 +//@ check-pass + +// Make sure we don't cycle error when normalizing types for tail expr drop order lint. + +#![deny(tail_expr_drop_order)] + +async fn test() -> Result<(), Box> { + Box::pin(test()).await?; + Ok(()) +} + +fn main() {} From 4a099b29cdb6a7841019406f0f2b5035a1fd9a08 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 5 Jan 2025 19:11:00 +0000 Subject: [PATCH 114/189] Don't do AccessDepth::Drop for types with no drop impl --- compiler/rustc_borrowck/src/lib.rs | 16 ++++-- .../tail_expr_drop_order-on-thread-local.rs | 56 +++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 tests/ui/drop/tail_expr_drop_order-on-thread-local.rs diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index df3368bdd30ae..8b3870e5cc605 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1166,10 +1166,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn check_backward_incompatible_drop( &mut self, location: Location, - place_span: (Place<'tcx>, Span), + (place, place_span): (Place<'tcx>, Span), state: &BorrowckDomain, ) { - let sd = AccessDepth::Drop; + let tcx = self.infcx.tcx; + // If this type does not need `Drop`, then treat it like a `StorageDead`. + // This is needed because we track the borrows of refs to thread locals, + // and we'll ICE because we don't track borrows behind shared references. + let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) { + AccessDepth::Drop + } else { + AccessDepth::Shallow(None) + }; let borrows_in_scope = self.borrows_in_scope(location, state); @@ -1179,7 +1187,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self, self.infcx.tcx, self.body, - (sd, place_span.0), + (sd, place), self.borrow_set, |borrow_index| borrows_in_scope.contains(borrow_index), |this, _borrow_index, borrow| { @@ -1190,7 +1198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { this.infcx.tcx.emit_node_span_lint( TAIL_EXPR_DROP_ORDER, CRATE_HIR_ID, - place_span.1, + place_span, session_diagnostics::TailExprDropOrder { borrowed }, ); // We may stop at the first case diff --git a/tests/ui/drop/tail_expr_drop_order-on-thread-local.rs b/tests/ui/drop/tail_expr_drop_order-on-thread-local.rs new file mode 100644 index 0000000000000..e38175fd1b653 --- /dev/null +++ b/tests/ui/drop/tail_expr_drop_order-on-thread-local.rs @@ -0,0 +1,56 @@ +//@ check-pass + +#![feature(thread_local)] +#![deny(tail_expr_drop_order)] + +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +pub struct Global; + +#[thread_local] +static REENTRANCY_STATE: State = State { marker: PhantomData, controller: Global }; + +pub struct Token(PhantomData<*mut ()>); + +pub fn with_mut(f: impl FnOnce(&mut Token) -> T) -> T { + f(&mut REENTRANCY_STATE.borrow_mut()) +} + +pub struct State { + marker: PhantomData<*mut ()>, + controller: T, +} + +impl State { + pub fn borrow_mut(&self) -> TokenMut<'_, T> { + todo!() + } +} + +pub struct TokenMut<'a, T: ?Sized = Global> { + state: &'a State, + token: Token, +} + +impl Deref for TokenMut<'_, T> { + type Target = Token; + + fn deref(&self) -> &Self::Target { + todo!() + } +} + +impl DerefMut for TokenMut<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + todo!() + } +} + +impl Drop for TokenMut<'_, T> { + fn drop(&mut self) { + todo!() + } +} + +fn main() {} From c55eefe8bc51f302cfc89d375198ca7211d4709b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 6 Jan 2025 03:25:45 +0000 Subject: [PATCH 115/189] Try to explain borrow for tail expr temporary drop order change in 2024 --- compiler/rustc_borrowck/messages.ftl | 5 ++- .../src/diagnostics/explain_borrow.rs | 18 ++++----- .../rustc_borrowck/src/diagnostics/mod.rs | 11 +++--- .../src/diagnostics/region_name.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 19 +++++++--- ...hod_1.ElaborateDrops.after.panic-abort.mir | 1 + ...od_1.ElaborateDrops.after.panic-unwind.mir | 1 + .../lint-tail-expr-drop-order-borrowck.rs | 26 ++++++++++--- .../lint-tail-expr-drop-order-borrowck.stderr | 38 ++++++++++++------- 9 files changed, 81 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index c1d5af59b1b5b..ada20e5c614f8 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -213,8 +213,9 @@ borrowck_suggest_create_fresh_reborrow = borrowck_suggest_iterate_over_slice = consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop -borrowck_tail_expr_drop_order = a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - .label = consider using a `let` binding to create a longer lived value; or replacing the `{"{"} .. {"}"}` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe {"{"} .. {"}"}` +borrowck_tail_expr_drop_order = relative drop order changing in Rust 2024 + .label = this temporary value will be dropped at the end of the block + .note = consider using a `let` binding to ensure the value will live long enough borrowck_ty_no_impl_copy = {$is_partial_move -> diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 48f28f3f1de95..a52dc447d7685 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -5,7 +5,7 @@ use std::assert_matches::assert_matches; -use rustc_errors::{Applicability, Diag}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_infer::infer::NllRegionVariableOrigin; @@ -61,10 +61,10 @@ impl<'tcx> BorrowExplanation<'tcx> { pub(crate) fn is_explained(&self) -> bool { !matches!(self, BorrowExplanation::Unexplained) } - pub(crate) fn add_explanation_to_diagnostic( + pub(crate) fn add_explanation_to_diagnostic( &self, cx: &MirBorrowckCtxt<'_, '_, 'tcx>, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, borrow_desc: &str, borrow_span: Option, multiple_borrow_span: Option<(Span, Span)>, @@ -346,10 +346,10 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_object_lifetime_default_note( + fn add_object_lifetime_default_note( &self, tcx: TyCtxt<'tcx>, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, unsize_ty: Ty<'tcx>, ) { if let ty::Adt(def, args) = unsize_ty.kind() { @@ -403,9 +403,9 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_lifetime_bound_suggestion_to_diagnostic( + fn add_lifetime_bound_suggestion_to_diagnostic( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, category: &ConstraintCategory<'tcx>, span: Span, region_name: &RegionName, @@ -432,14 +432,14 @@ impl<'tcx> BorrowExplanation<'tcx> { } } -fn suggest_rewrite_if_let( +fn suggest_rewrite_if_let( tcx: TyCtxt<'_>, expr: &hir::Expr<'_>, pat: &str, init: &hir::Expr<'_>, conseq: &hir::Expr<'_>, alt: Option<&hir::Expr<'_>>, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, ) { let source_map = tcx.sess.source_map(); err.span_note( diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0286ea6cd9dca..d9d9ea75994f1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; use rustc_index::IndexSlice; @@ -626,9 +626,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates /// implicitly introduce an "outlives `'static`" constraint. - fn add_placeholder_from_predicate_note( + fn add_placeholder_from_predicate_note( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, path: &[OutlivesConstraint<'tcx>], ) { let predicate_span = path.iter().find_map(|constraint| { @@ -651,9 +651,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Add a label to region errors and borrow explanations when outlives constraints arise from /// proving a type implements `Sized` or `Copy`. - fn add_sized_or_copy_bound_info( + fn add_sized_or_copy_bound_info( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, G>, blamed_category: ConstraintCategory<'tcx>, path: &[OutlivesConstraint<'tcx>], ) { @@ -1042,6 +1042,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { kind, }; } + normal_ret } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index bdb880b2bced3..9349b46ec5b0c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Display}; use std::iter; use rustc_data_structures::fx::IndexEntry; -use rustc_errors::Diag; +use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; @@ -108,7 +108,7 @@ impl RegionName { } } - pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_>) { + pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_, G>) { match &self.source { RegionNameSource::NamedLateParamRegion(span) | RegionNameSource::NamedEarlyParamRegion(span) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8b3870e5cc605..f90f75141026f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -24,6 +24,7 @@ use std::ops::{ControlFlow, Deref}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; +use rustc_errors::LintDiagnostic; use rustc_hir as hir; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; @@ -1192,17 +1193,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { |borrow_index| borrows_in_scope.contains(borrow_index), |this, _borrow_index, borrow| { if matches!(borrow.kind, BorrowKind::Fake(_)) { - return Control::Continue; + return ControlFlow::Continue(()); } let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span(); - this.infcx.tcx.emit_node_span_lint( + let explain = this.explain_why_borrow_contains_point( + location, + borrow, + Some((WriteKind::StorageDeadOrDrop, place)), + ); + this.infcx.tcx.node_span_lint( TAIL_EXPR_DROP_ORDER, CRATE_HIR_ID, - place_span, - session_diagnostics::TailExprDropOrder { borrowed }, + borrowed, + |diag| { + session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag); + explain.add_explanation_to_diagnostic(&this, diag, "", None, None); + }, ); // We may stop at the first case - Control::Break + ControlFlow::Break(()) }, ); } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir index e9bbe30bd774f..ee6e16d20fd8d 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir @@ -74,6 +74,7 @@ fn method_1(_1: Guard) -> () { bb7: { backward incompatible drop(_2); + backward incompatible drop(_4); backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir index e9bbe30bd774f..ee6e16d20fd8d 100644 --- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir @@ -74,6 +74,7 @@ fn method_1(_1: Guard) -> () { bb7: { backward incompatible drop(_2); + backward incompatible drop(_4); backward incompatible drop(_5); goto -> bb21; } diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs index 1bd5655d7fe1d..6f64d83f8a0c3 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.rs @@ -7,18 +7,20 @@ fn should_lint_with_potential_borrowck_err() { let _ = { String::new().as_str() }.len(); - //~^ ERROR: a temporary value will be dropped here + //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 - //~| NOTE: consider using a `let` binding + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used by call //~| NOTE: for more information, see } fn should_lint_with_unsafe_block() { fn f(_: usize) {} f(unsafe { String::new().as_str() }.len()); - //~^ ERROR: a temporary value will be dropped here + //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 - //~| NOTE: consider using a `let` binding + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used by call //~| NOTE: for more information, see } @@ -27,11 +29,23 @@ fn should_lint_with_big_block() { fn f(_: T) {} f({ &mut || 0 - //~^ ERROR: a temporary value will be dropped here + //~^ ERROR: relative drop order changing //~| WARN: this changes meaning in Rust 2024 - //~| NOTE: consider using a `let` binding + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used here //~| NOTE: for more information, see }) } +fn another_temp_that_is_copy_in_arg() { + fn f() {} + fn g(_: &()) {} + g({ &f() }); + //~^ ERROR: relative drop order changing + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this temporary value will be dropped at the end of the block + //~| borrow later used by call + //~| NOTE: for more information, see +} + fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr index 98ef0547c9075..a55e366dd0be1 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order-borrowck.stderr @@ -1,10 +1,10 @@ -error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - --> $DIR/lint-tail-expr-drop-order-borrowck.rs:9:36 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:9:15 | LL | let _ = { String::new().as_str() }.len(); - | ------------- ^ + | ^^^^^^^^^^^^^ --- borrow later used by call | | - | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | this temporary value will be dropped at the end of the block | = warning: this changes meaning in Rust 2024 = note: for more information, see @@ -14,27 +14,39 @@ note: the lint level is defined here LL | #![deny(tail_expr_drop_order)] | ^^^^^^^^^^^^^^^^^^^^ -error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - --> $DIR/lint-tail-expr-drop-order-borrowck.rs:18:37 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:19:16 | LL | f(unsafe { String::new().as_str() }.len()); - | ------------- ^ + | ^^^^^^^^^^^^^ --- borrow later used by call | | - | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | this temporary value will be dropped at the end of the block | = warning: this changes meaning in Rust 2024 = note: for more information, see -error: a temporary value will be dropped here before the execution exits the block in Edition 2024, which will raise borrow checking error - --> $DIR/lint-tail-expr-drop-order-borrowck.rs:29:17 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:31:9 | LL | &mut || 0 - | --------^ + | ^^^^^^^^^ | | - | consider using a `let` binding to create a longer lived value; or replacing the `{ .. }` block with curly brackets `( .. )`; or folding the rest of the expression into the surrounding `unsafe { .. }` + | this temporary value will be dropped at the end of the block + | borrow later used here | = warning: this changes meaning in Rust 2024 = note: for more information, see -error: aborting due to 3 previous errors +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order-borrowck.rs:43:9 + | +LL | g({ &f() }); + | - ^^^^ this temporary value will be dropped at the end of the block + | | + | borrow later used by call + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see + +error: aborting due to 4 previous errors From 49942961a7142e11289d8aaece3803fe7442f3d4 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 7 Jan 2025 23:38:01 +0000 Subject: [PATCH 116/189] Only test proc-macro invalid compile flags with panic=unwind Fuchsia explicitly builds rust and all rust targets with `-C panic=abort` to minimize code generation size. However, when compiling a proc-macro with this setting it can cause a warning to be emitted, which breaks `tests/ui/invalid-compile-flags/crate-type-flag.rs`. This hasn't been a problem in the past for us since we compile our proc macros on host, rather than inside Fuchsia. This attempts to fix the issue by explicitly requiring that we're using the unwinder when compiling this test to avoid the warning being emitted. Fixes #135223 --- compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh | 1 - tests/ui/invalid-compile-flags/crate-type-flag.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 442d61c6ade17..e569da90cf7b4 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -123,7 +123,6 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift -rm tests/ui/invalid-compile-flags/crate-type-flag.rs # warning about proc-macros and panic=abort # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended diff --git a/tests/ui/invalid-compile-flags/crate-type-flag.rs b/tests/ui/invalid-compile-flags/crate-type-flag.rs index 42bd72cbfbf52..bc7a0bc46c3a8 100644 --- a/tests/ui/invalid-compile-flags/crate-type-flag.rs +++ b/tests/ui/invalid-compile-flags/crate-type-flag.rs @@ -30,6 +30,7 @@ //@[bin] check-pass //@[proc_dash_macro] ignore-wasm (proc-macro is not supported) +//@[proc_dash_macro] needs-unwind (panic=abort causes warning to be emitted) //@[proc_dash_macro] compile-flags: --crate-type=proc-macro //@[proc_dash_macro] check-pass From 3998964879e709cfc1728edb3e596c3ec0a7696e Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 7 Jan 2025 23:38:01 +0000 Subject: [PATCH 117/189] Only test proc-macro invalid compile flags with panic=unwind Fuchsia explicitly builds rust and all rust targets with `-C panic=abort` to minimize code generation size. However, when compiling a proc-macro with this setting it can cause a warning to be emitted, which breaks `tests/ui/invalid-compile-flags/crate-type-flag.rs`. This hasn't been a problem in the past for us since we compile our proc macros on host, rather than inside Fuchsia. This attempts to fix the issue by explicitly requiring that we're using the unwinder when compiling this test to avoid the warning being emitted. Fixes #135223 --- scripts/test_rustc_tests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 442d61c6ade17..e569da90cf7b4 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -123,7 +123,6 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift -rm tests/ui/invalid-compile-flags/crate-type-flag.rs # warning about proc-macros and panic=abort # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended From c64f859521d9f86c96144f487201055b2146e19f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 29 Dec 2024 04:42:21 +0000 Subject: [PATCH 118/189] Implement const Destruct in old solver --- compiler/rustc_middle/src/ty/mod.rs | 4 +- .../src/solve/assembly/structural_traits.rs | 2 + .../src/traits/effects.rs | 106 +++++++++++++++++- tests/ui/consts/fn_trait_refs.stderr | 93 ++------------- tests/ui/consts/promoted_const_call.stderr | 4 + .../impl-trait/normalize-tait-in-const.stderr | 19 +--- .../traits/const-traits/const-drop-bound.rs | 3 +- .../const-traits/const-drop-bound.stderr | 17 --- .../const-drop-fail-2.precise.stderr | 9 +- .../const-drop-fail-2.stock.stderr | 9 +- ...err => const-drop-fail.new_precise.stderr} | 8 +- ...tderr => const-drop-fail.new_stock.stderr} | 8 +- .../const-drop-fail.old_precise.stderr | 33 ++++++ .../const-drop-fail.old_stock.stderr | 33 ++++++ .../ui/traits/const-traits/const-drop-fail.rs | 7 +- 15 files changed, 222 insertions(+), 133 deletions(-) delete mode 100644 tests/ui/traits/const-traits/const-drop-bound.stderr rename tests/ui/traits/const-traits/{const-drop-fail.precise.stderr => const-drop-fail.new_precise.stderr} (87%) rename tests/ui/traits/const-traits/{const-drop-fail.stock.stderr => const-drop-fail.new_stock.stderr} (87%) create mode 100644 tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr create mode 100644 tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5e929fbec0bf8..2d69386176b80 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1417,8 +1417,8 @@ impl Hash for FieldDef { impl<'tcx> FieldDef { /// Returns the type of this field. The resulting type is not normalized. The `arg` is /// typically obtained via the second field of [`TyKind::Adt`]. - pub fn ty(&self, tcx: TyCtxt<'tcx>, arg: GenericArgsRef<'tcx>) -> Ty<'tcx> { - tcx.type_of(self.did).instantiate(tcx, arg) + pub fn ty(&self, tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { + tcx.type_of(self.did).instantiate(tcx, args) } /// Computes the `Ident` of this variant by looking up the `Span` diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 7da4f5e010754..3c5d9b95e772d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -712,6 +712,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( } } +// NOTE: Keep this in sync with `evaluate_host_effect_for_destruct_goal` in +// the old solver, for as long as that exists. pub(in crate::solve) fn const_conditions_for_destruct( cx: I, self_ty: I::Ty, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 0ac24eb54e748..b32909efe0be7 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -1,4 +1,4 @@ -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::traits::{ ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation, @@ -48,6 +48,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_builtin_impls(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + match evaluate_host_effect_from_selection_candiate(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), @@ -228,6 +234,104 @@ fn evaluate_host_effect_from_item_bounds<'tcx>( } } +fn evaluate_host_effect_from_builtin_impls<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result>, EvaluationFailure> { + match selcx.tcx().as_lang_item(obligation.predicate.def_id()) { + Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation), + _ => Err(EvaluationFailure::NoSolution), + } +} + +// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver. +fn evaluate_host_effect_for_destruct_goal<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result>, EvaluationFailure> { + let tcx = selcx.tcx(); + let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None); + let self_ty = obligation.predicate.self_ty(); + + let const_conditions = match *self_ty.kind() { + // An ADT is `~const Destruct` only if all of the fields are, + // *and* if there is a `Drop` impl, that `Drop` impl is also `~const`. + ty::Adt(adt_def, args) => { + let mut const_conditions: ThinVec<_> = adt_def + .all_fields() + .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)])) + .collect(); + match adt_def.destructor(tcx).map(|dtor| dtor.constness) { + // `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`. + Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), + // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. + Some(hir::Constness::Const) => { + let drop_def_id = tcx.require_lang_item(LangItem::Drop, None); + let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); + const_conditions.push(drop_trait_ref); + } + // No `Drop` impl, no need to require anything else. + None => {} + } + const_conditions + } + + ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => { + thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [ty])] + } + + ty::Tuple(tys) => { + tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect() + } + + // Trivially implement `~const Destruct` + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Str + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Never + | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) + | ty::Error(_) => thin_vec![], + + // Coroutines and closures could implement `~const Drop`, + // but they don't really need to right now. + ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution), + + // FIXME(unsafe_binders): Unsafe binders could implement `~const Drop` + // if their inner type implements it. + ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution), + + ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => { + return Err(EvaluationFailure::NoSolution); + } + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + }; + + Ok(const_conditions + .into_iter() + .map(|trait_ref| { + obligation.with( + tcx, + ty::Binder::dummy(trait_ref) + .to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }) + .collect()) +} + fn evaluate_host_effect_from_selection_candiate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index e0dbecff8e587..d688bfbde2bc2 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -155,90 +155,21 @@ note: `FnMut` can't be used with `~const` because it isn't annotated with `#[con --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: the trait bound `fn() -> i32 {one}: const Destruct` is not satisfied - --> $DIR/fn_trait_refs.rs:70:32 +error[E0015]: cannot call non-const operator in constants + --> $DIR/fn_trait_refs.rs:71:17 | -LL | let test_one = test_fn(one); - | ------- ^^^ - | | - | required by a bound introduced by this call +LL | assert!(test_one == (1, 1, 1)); + | ^^^^^^^^^^^^^^^^^^^^^ | -note: required by a bound in `test_fn` - --> $DIR/fn_trait_refs.rs:35:24 - | -LL | const fn test_fn(mut f: T) -> (T::Output, T::Output, T::Output) - | ------- required by a bound in this function -LL | where -LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ required by this bound in `test_fn` - -error[E0277]: the trait bound `fn() -> i32 {two}: const Destruct` is not satisfied - --> $DIR/fn_trait_refs.rs:73:36 - | -LL | let test_two = test_fn_mut(two); - | ----------- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `test_fn_mut` - --> $DIR/fn_trait_refs.rs:49:27 - | -LL | const fn test_fn_mut(mut f: T) -> (T::Output, T::Output) - | ----------- required by a bound in this function -LL | where -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ required by this bound in `test_fn_mut` + = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied - --> $DIR/fn_trait_refs.rs:39:19 - | -LL | tester_fn(&f), - | --------- ^^ - | | - | required by a bound introduced by this call +error[E0015]: cannot call non-const operator in constants + --> $DIR/fn_trait_refs.rs:74:17 | -note: required by a bound in `tester_fn` - --> $DIR/fn_trait_refs.rs:14:24 +LL | assert!(test_two == (2, 2)); + | ^^^^^^^^^^^^^^^^^^ | -LL | const fn tester_fn(f: T) -> T::Output - | --------- required by a bound in this function -LL | where -LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ required by this bound in `tester_fn` - -error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied - --> $DIR/fn_trait_refs.rs:41:23 - | -LL | tester_fn_mut(&f), - | ------------- ^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `tester_fn_mut` - --> $DIR/fn_trait_refs.rs:21:27 - | -LL | const fn tester_fn_mut(mut f: T) -> T::Output - | ------------- required by a bound in this function -LL | where -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ required by this bound in `tester_fn_mut` - -error[E0277]: the trait bound `&mut T: ~const Destruct` is not satisfied - --> $DIR/fn_trait_refs.rs:53:23 - | -LL | tester_fn_mut(&mut f), - | ------------- ^^^^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `tester_fn_mut` - --> $DIR/fn_trait_refs.rs:21:27 - | -LL | const fn tester_fn_mut(mut f: T) -> T::Output - | ------------- required by a bound in this function -LL | where -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ required by this bound in `tester_fn_mut` + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const closure in constant functions --> $DIR/fn_trait_refs.rs:16:5 @@ -264,7 +195,7 @@ LL | f() | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 25 previous errors +error: aborting due to 22 previous errors -Some errors have detailed explanations: E0015, E0277, E0635. +Some errors have detailed explanations: E0015, E0635. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/promoted_const_call.stderr b/tests/ui/consts/promoted_const_call.stderr index dd70bb601c47d..40c6d083b066f 100644 --- a/tests/ui/consts/promoted_const_call.stderr +++ b/tests/ui/consts/promoted_const_call.stderr @@ -5,6 +5,10 @@ LL | let _: &'static _ = &id(&Panic); | ^^^^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constants + | + = note: see issue #133214 for more information + = help: add `#![feature(const_destruct)]` 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[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call.rs:16:26 diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 0f79cefeaecb7..f4e8a872cec12 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -17,20 +17,6 @@ note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_ --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: the trait bound `for<'a, 'b> fn(&'a foo::Alias<'b>) {foo}: const Destruct` is not satisfied - --> $DIR/normalize-tait-in-const.rs:33:19 - | -LL | with_positive(foo); - | ------------- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `with_positive` - --> $DIR/normalize-tait-in-const.rs:26:62 - | -LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^ required by this bound in `with_positive` - error[E0015]: cannot call non-const closure in constant functions --> $DIR/normalize-tait-in-const.rs:27:5 | @@ -39,7 +25,6 @@ LL | fun(filter_positive()); | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0015, E0277. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-drop-bound.rs b/tests/ui/traits/const-traits/const-drop-bound.rs index 398fb39064055..4819da7c3a403 100644 --- a/tests/ui/traits/const-traits/const-drop-bound.rs +++ b/tests/ui/traits/const-traits/const-drop-bound.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 -// FIXME check-pass +//@ check-pass #![feature(const_trait_impl)] #![feature(const_precise_live_drops, const_destruct)] diff --git a/tests/ui/traits/const-traits/const-drop-bound.stderr b/tests/ui/traits/const-traits/const-drop-bound.stderr deleted file mode 100644 index 78ba0279566de..0000000000000 --- a/tests/ui/traits/const-traits/const-drop-bound.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `Foo: ~const Destruct` is not satisfied - --> $DIR/const-drop-bound.rs:23:9 - | -LL | foo(res) - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/const-drop-bound.rs:9:61 - | -LL | const fn foo(res: Result) -> Option where E: ~const Destruct { - | ^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr index 7b2cafb612441..2b5e66b1a086c 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr @@ -1,9 +1,16 @@ -error[E0277]: the trait bound `ConstDropImplWithBounds: const Destruct` is not satisfied +error[E0277]: the trait bound `NonTrivialDrop: const A` is not satisfied --> $DIR/const-drop-fail-2.rs:31:23 | LL | const _: () = check::>( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: required for `ConstDropImplWithBounds` to implement `const Drop` + --> $DIR/const-drop-fail-2.rs:25:25 + | +LL | impl const Drop for ConstDropImplWithBounds { + | ------ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here note: required by a bound in `check` --> $DIR/const-drop-fail-2.rs:21:19 | diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr index 7b2cafb612441..2b5e66b1a086c 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr @@ -1,9 +1,16 @@ -error[E0277]: the trait bound `ConstDropImplWithBounds: const Destruct` is not satisfied +error[E0277]: the trait bound `NonTrivialDrop: const A` is not satisfied --> $DIR/const-drop-fail-2.rs:31:23 | LL | const _: () = check::>( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: required for `ConstDropImplWithBounds` to implement `const Drop` + --> $DIR/const-drop-fail-2.rs:25:25 + | +LL | impl const Drop for ConstDropImplWithBounds { + | ------ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here note: required by a bound in `check` --> $DIR/const-drop-fail-2.rs:21:19 | diff --git a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr similarity index 87% rename from tests/ui/traits/const-traits/const-drop-fail.precise.stderr rename to tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr index 8b3e777a0b098..682f48fe07af6 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.new_precise.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:32:5 + --> $DIR/const-drop-fail.rs:33:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +8,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:23:19 + --> $DIR/const-drop-fail.rs:24:19 | LL | const fn check(_: T) {} | ^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:34:5 + --> $DIR/const-drop-fail.rs:35:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:23:19 + --> $DIR/const-drop-fail.rs:24:19 | LL | const fn check(_: T) {} | ^^^^^^ required by this bound in `check` diff --git a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr similarity index 87% rename from tests/ui/traits/const-traits/const-drop-fail.stock.stderr rename to tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr index 8b3e777a0b098..682f48fe07af6 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.new_stock.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:32:5 + --> $DIR/const-drop-fail.rs:33:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -8,13 +8,13 @@ LL | NonTrivialDrop, | ^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:23:19 + --> $DIR/const-drop-fail.rs:24:19 | LL | const fn check(_: T) {} | ^^^^^^ required by this bound in `check` error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied - --> $DIR/const-drop-fail.rs:34:5 + --> $DIR/const-drop-fail.rs:35:5 | LL | const _: () = check($exp); | ----- required by a bound introduced by this call @@ -23,7 +23,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `check` - --> $DIR/const-drop-fail.rs:23:19 + --> $DIR/const-drop-fail.rs:24:19 | LL | const fn check(_: T) {} | ^^^^^^ required by this bound in `check` diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr new file mode 100644 index 0000000000000..682f48fe07af6 --- /dev/null +++ b/tests/ui/traits/const-traits/const-drop-fail.old_precise.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied + --> $DIR/const-drop-fail.rs:33:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | NonTrivialDrop, + | ^^^^^^^^^^^^^^ + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:24:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ required by this bound in `check` + +error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied + --> $DIR/const-drop-fail.rs:35:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:24:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ required by this bound in `check` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr new file mode 100644 index 0000000000000..682f48fe07af6 --- /dev/null +++ b/tests/ui/traits/const-traits/const-drop-fail.old_stock.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied + --> $DIR/const-drop-fail.rs:33:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | NonTrivialDrop, + | ^^^^^^^^^^^^^^ + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:24:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ required by this bound in `check` + +error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied + --> $DIR/const-drop-fail.rs:35:5 + | +LL | const _: () = check($exp); + | ----- required by a bound introduced by this call +... +LL | ConstImplWithDropGlue(NonTrivialDrop), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `check` + --> $DIR/const-drop-fail.rs:24:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ required by this bound in `check` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs index 5e05b9db474a6..a7f3d5654de93 100644 --- a/tests/ui/traits/const-traits/const-drop-fail.rs +++ b/tests/ui/traits/const-traits/const-drop-fail.rs @@ -1,8 +1,9 @@ -//@ compile-flags: -Znext-solver -//@ revisions: stock precise +//@[new_precise] compile-flags: -Znext-solver +//@[new_stock] compile-flags: -Znext-solver +//@ revisions: new_stock old_stock new_precise old_precise #![feature(const_trait_impl, const_destruct)] -#![cfg_attr(precise, feature(const_precise_live_drops))] +#![cfg_attr(any(new_precise, old_precise), feature(const_precise_live_drops))] use std::marker::{Destruct, PhantomData}; From 4ae92b7adbafd018bf0c829a4691ffbb3933d8f0 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 6 Jan 2025 20:28:08 +0100 Subject: [PATCH 119/189] update version placeholders --- compiler/rustc_feature/src/accepted.rs | 6 +++--- compiler/rustc_feature/src/removed.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 22 +++++++++++----------- library/alloc/src/boxed.rs | 6 +++--- library/core/src/alloc/layout.rs | 10 +++++----- library/core/src/hash/mod.rs | 4 ++-- library/core/src/iter/traits/collect.rs | 2 +- library/core/src/mem/maybe_uninit.rs | 2 +- library/core/src/mem/mod.rs | 6 +++--- library/core/src/num/f32.rs | 22 +++++++++++----------- library/core/src/num/f64.rs | 22 +++++++++++----------- library/core/src/num/mod.rs | 8 ++++---- library/core/src/num/nonzero.rs | 4 ++-- library/core/src/ops/async_function.rs | 16 ++++++++-------- library/core/src/prelude/mod.rs | 4 ++-- library/core/src/ptr/mod.rs | 4 ++-- library/core/src/ptr/mut_ptr.rs | 2 +- library/core/src/ptr/non_null.rs | 4 ++-- library/core/src/slice/mod.rs | 2 +- library/core/src/task/wake.rs | 6 +++--- library/std/src/collections/hash/map.rs | 2 +- library/std/src/collections/hash/set.rs | 2 +- library/std/src/env.rs | 2 +- library/std/src/io/error.rs | 4 ++-- library/std/src/prelude/common.rs | 2 +- library/std/src/prelude/mod.rs | 4 ++-- src/doc/rustc/src/check-cfg.md | 2 +- 27 files changed, 86 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 776de1988ccdc..217a7aeb2d7f7 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -73,7 +73,7 @@ declare_features! ( /// Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. (accepted, async_await, "1.39.0", Some(50547)), /// Allows `async || body` closures. - (accepted, async_closure, "CURRENT_RUSTC_VERSION", Some(62290)), + (accepted, async_closure, "1.85.0", Some(62290)), /// Allows async functions to be declared, implemented, and used in traits. (accepted, async_fn_in_trait, "1.75.0", Some(91611)), /// Allows all literals in attribute lists and values of key-value pairs. @@ -176,7 +176,7 @@ declare_features! ( /// Allows using the `#[diagnostic]` attribute tool namespace (accepted, diagnostic_namespace, "1.78.0", Some(111996)), /// Controls errors in trait implementations. - (accepted, do_not_recommend, "CURRENT_RUSTC_VERSION", Some(51992)), + (accepted, do_not_recommend, "1.85.0", Some(51992)), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146)), /// Allows `..` in tuple (struct) patterns. @@ -199,7 +199,7 @@ declare_features! ( (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), /// Allows using `efiapi`, `aapcs`, `sysv64` and `win64` as calling /// convention for functions with varargs. - (accepted, extended_varargs_abi_support, "CURRENT_RUSTC_VERSION", Some(100189)), + (accepted, extended_varargs_abi_support, "1.85.0", Some(100189)), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660)), /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 388ed9d08fa67..9aa59375706b4 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -120,7 +120,7 @@ declare_features! ( /// Allows defining generators. (removed, generators, "1.21.0", Some(43122), Some("renamed to `coroutines`")), /// An extension to the `generic_associated_types` feature, allowing incomplete features. - (removed, generic_associated_types_extended, "CURRENT_RUSTC_VERSION", Some(95451), + (removed, generic_associated_types_extended, "1.85.0", Some(95451), Some( "feature needs overhaul and reimplementation pending \ better implied higher-ranked implied bounds support" diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8cc4c18c02abf..fb83487c9394b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -333,7 +333,7 @@ declare_features! ( (unstable, hexagon_target_feature, "1.27.0", Some(44839)), (unstable, lahfsahf_target_feature, "1.78.0", Some(44839)), (unstable, loongarch_target_feature, "1.73.0", Some(44839)), - (unstable, m68k_target_feature, "CURRENT_RUSTC_VERSION", Some(134328)), + (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), @@ -344,7 +344,7 @@ declare_features! ( (unstable, sse4a_target_feature, "1.27.0", Some(44839)), (unstable, tbm_target_feature, "1.27.0", Some(44839)), (unstable, wasm_target_feature, "1.30.0", Some(44839)), - (unstable, x87_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (unstable, x87_target_feature, "1.85.0", Some(44839)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! @@ -380,11 +380,11 @@ declare_features! ( /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Enables experimental register support in inline assembly. - (unstable, asm_experimental_reg, "CURRENT_RUSTC_VERSION", Some(133416)), + (unstable, asm_experimental_reg, "1.85.0", Some(133416)), /// Allows using `label` operands in inline assembly. (unstable, asm_goto, "1.78.0", Some(119364)), /// Allows using `label` operands in inline assembly together with output operands. - (unstable, asm_goto_with_outputs, "CURRENT_RUSTC_VERSION", Some(119364)), + (unstable, asm_goto_with_outputs, "1.85.0", Some(119364)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), /// Allows users to enforce equality of associated constants `TraitImpl`. @@ -392,13 +392,13 @@ declare_features! ( /// Allows associated type defaults. (unstable, associated_type_defaults, "1.2.0", Some(29661)), /// Allows async functions to be called from `dyn Trait`. - (incomplete, async_fn_in_dyn_trait, "CURRENT_RUSTC_VERSION", Some(133119)), + (incomplete, async_fn_in_dyn_trait, "1.85.0", Some(133119)), /// Allows `#[track_caller]` on async functions. (unstable, async_fn_track_caller, "1.73.0", Some(110011)), /// Allows `for await` loops. (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows `async` trait bound modifier. - (unstable, async_trait_bounds, "CURRENT_RUSTC_VERSION", Some(62290)), + (unstable, async_trait_bounds, "1.85.0", Some(62290)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg()]`. @@ -436,7 +436,7 @@ declare_features! ( /// Allows `const || {}` closures in const contexts. (incomplete, const_closures, "1.68.0", Some(106003)), /// Allows using `~const Destruct` bounds and calling drop impls in const contexts. - (unstable, const_destruct, "CURRENT_RUSTC_VERSION", Some(133214)), + (unstable, const_destruct, "1.85.0", Some(133214)), /// Allows `for _ in _` loops in const contexts. (unstable, const_for, "1.56.0", Some(87575)), /// Be more precise when looking for live drops in a const context. @@ -460,7 +460,7 @@ declare_features! ( (unstable, decl_macro, "1.17.0", Some(39412)), /// Allows the use of default values on struct definitions and the construction of struct /// literals with the functional update syntax without a base. - (unstable, default_field_values, "CURRENT_RUSTC_VERSION", Some(132162)), + (unstable, default_field_values, "1.85.0", Some(132162)), /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. @@ -510,7 +510,7 @@ declare_features! ( /// Allows registering static items globally, possibly across crates, to iterate over at runtime. (unstable, global_registration, "1.80.0", Some(125119)), /// Allows using guards in patterns. - (incomplete, guard_patterns, "CURRENT_RUSTC_VERSION", Some(129967)), + (incomplete, guard_patterns, "1.85.0", Some(129967)), /// Allows using `..=X` as a patterns in slices. (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)), /// Allows `if let` guard in match arms. @@ -639,9 +639,9 @@ declare_features! ( /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), /// Allows using `unsafe<'a> &'a T` unsafe binder types. - (incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)), + (incomplete, unsafe_binders, "1.85.0", Some(130516)), /// Allows declaring fields `unsafe`. - (incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)), + (incomplete, unsafe_fields, "1.85.0", Some(132922)), /// Allows const generic parameters to be defined with types that /// are not `Sized`, e.g. `fn foo() {`. (incomplete, unsized_const_params, "1.82.0", Some(95174)), diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 0f66217b5cb33..dcc1d0234d365 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2029,7 +2029,7 @@ impl + ?Sized, A: Allocator> Fn for Box { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl + ?Sized, A: Allocator> AsyncFnOnce for Box { type Output = F::Output; type CallOnceFuture = F::CallOnceFuture; @@ -2040,7 +2040,7 @@ impl + ?Sized, A: Allocator> AsyncFnOnce } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl + ?Sized, A: Allocator> AsyncFnMut for Box { type CallRefFuture<'a> = F::CallRefFuture<'a> @@ -2053,7 +2053,7 @@ impl + ?Sized, A: Allocator> AsyncFnMut f } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl + ?Sized, A: Allocator> AsyncFn for Box { extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index e6f39db9dced3..21dfdd926e0af 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -178,7 +178,7 @@ impl Layout { /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { @@ -252,7 +252,7 @@ impl Layout { /// Returns an error if the combination of `self.size()` and the given /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn align_to(&self, align: usize) -> Result { if let Some(align) = Alignment::new(align) { @@ -327,7 +327,7 @@ impl Layout { /// This is equivalent to adding the result of `padding_needed_for` /// to the layout's current size. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[must_use = "this returns a new `Layout`, \ without modifying the original"] #[inline] @@ -426,7 +426,7 @@ impl Layout { /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16]))); /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = Alignment::max(self.align, next.align); @@ -489,7 +489,7 @@ impl Layout { /// On arithmetic overflow or when the total size would exceed /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] - #[rustc_const_stable(feature = "const_alloc_layout", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")] #[inline] pub const fn array(n: usize) -> Result { // Reduce the amount of code we need to monomorphize per `T`. diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 84bbf985e8be4..b43cf68421594 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -752,10 +752,10 @@ pub struct BuildHasherDefault(marker::PhantomData H>); impl BuildHasherDefault { /// Creates a new BuildHasherDefault for Hasher `H`. - #[stable(feature = "build_hasher_default_const_new", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "build_hasher_default_const_new", since = "1.85.0")] #[rustc_const_stable( feature = "build_hasher_default_const_new", - since = "CURRENT_RUSTC_VERSION" + since = "1.85.0" )] pub const fn new() -> Self { BuildHasherDefault(marker::PhantomData) diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 73e6d93106096..97bb21c8a36e8 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -472,7 +472,7 @@ macro_rules! spec_tuple_impl { #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for \ 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in \ - CURRENT_RUSTC_VERSION."] + 1.85.0."] => ($ty_name, $var_name, $extend_ty_name, $cnt), ); }; diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 58fb5be5812c8..284a58c7278fd 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -507,7 +507,7 @@ impl MaybeUninit { /// ``` #[inline(always)] #[stable(feature = "maybe_uninit_write", since = "1.55.0")] - #[rustc_const_stable(feature = "const_maybe_uninit_write", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_maybe_uninit_write", since = "1.85.0")] pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 2d66e5c2f2a7a..b9bb6d6a13f7f 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -333,7 +333,7 @@ pub const fn size_of() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_size_of_val", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_size_of_val", since = "1.85.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] pub const fn size_of_val(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer @@ -484,7 +484,7 @@ pub const fn align_of() -> usize { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_align_of_val", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")] #[allow(deprecated)] pub const fn align_of_val(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer @@ -725,7 +725,7 @@ pub unsafe fn uninitialized() -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[rustc_diagnostic_item = "mem_swap"] pub const fn swap(x: &mut T, y: &mut T) { // SAFETY: `&mut` guarantees these are typed readable and writable diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 4c0d95f95e562..2b6adef65e94a 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -818,7 +818,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn recip(self) -> f32 { 1.0 / self @@ -836,7 +836,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_degrees(self) -> f32 { // Use a constant for better precision. @@ -856,7 +856,7 @@ impl f32 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_radians(self) -> f32 { const RADS_PER_DEG: f32 = consts::PI / 180.0; @@ -878,7 +878,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f32) -> f32 { intrinsics::maxnumf32(self, other) @@ -899,7 +899,7 @@ impl f32 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f32) -> f32 { intrinsics::minnumf32(self, other) @@ -988,8 +988,8 @@ impl f32 { /// assert_eq!((-5.5f32).midpoint(8.0), 1.25); /// ``` #[inline] - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f32) -> f32 { cfg_if! { // Allow faster implementation that have known good 64-bit float @@ -1396,7 +1396,7 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn clamp(mut self, min: f32, max: f32) -> f32 { const_assert!( @@ -1433,7 +1433,7 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f32 { // SAFETY: this is actually a safe intrinsic @@ -1458,7 +1458,7 @@ impl f32 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn signum(self) -> f32 { if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) } @@ -1493,7 +1493,7 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[inline] #[stable(feature = "copysign", since = "1.35.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] pub const fn copysign(self, sign: f32) -> f32 { // SAFETY: this is actually a safe intrinsic unsafe { intrinsics::copysignf32(self, sign) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 77ca56df06705..037b3afa6c46c 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -835,7 +835,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the operation, without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn recip(self) -> f64 { 1.0 / self @@ -853,7 +853,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_degrees(self) -> f64 { // The division here is correctly rounded with respect to the true @@ -874,7 +874,7 @@ impl f64 { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn to_radians(self) -> f64 { const RADS_PER_DEG: f64 = consts::PI / 180.0; @@ -896,7 +896,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f64) -> f64 { intrinsics::maxnumf64(self, other) @@ -917,7 +917,7 @@ impl f64 { /// ``` #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f64) -> f64 { intrinsics::minnumf64(self, other) @@ -1006,8 +1006,8 @@ impl f64 { /// assert_eq!((-5.5f64).midpoint(8.0), 1.25); /// ``` #[inline] - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f64) -> f64 { const LO: f64 = f64::MIN_POSITIVE * 2.; const HI: f64 = f64::MAX / 2.; @@ -1396,7 +1396,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn clamp(mut self, min: f64, max: f64) -> f64 { const_assert!( @@ -1433,7 +1433,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f64 { // SAFETY: this is actually a safe intrinsic @@ -1458,7 +1458,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn signum(self) -> f64 { if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) } @@ -1492,7 +1492,7 @@ impl f64 { /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "copysign", since = "1.35.0")] - #[rustc_const_stable(feature = "const_float_methods", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn copysign(self, sign: f64) -> f64 { // SAFETY: this is actually a safe intrinsic diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 1f5b8ce6c6e22..67d219654b969 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -138,8 +138,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -192,8 +192,8 @@ macro_rules! midpoint_impl { #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] /// ``` - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a9294306b1b61..926723b3dbab7 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1543,8 +1543,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "num_midpoint", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "num_midpoint", since = "1.85.0")] + #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 0073afd496070..2ee243ea85eb4 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -5,7 +5,7 @@ use crate::marker::Tuple; /// /// All `async fn` and functions returning futures implement this trait. #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -20,7 +20,7 @@ pub trait AsyncFn: AsyncFnMut { /// /// All `async fn` and functions returning futures implement this trait. #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -42,7 +42,7 @@ pub trait AsyncFnMut: AsyncFnOnce { /// /// All `async fn` and functions returning futures implement this trait. #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -68,7 +68,7 @@ mod impls { use crate::marker::Tuple; #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl AsyncFn for &F where F: AsyncFn, @@ -79,7 +79,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl AsyncFnMut for &F where F: AsyncFn, @@ -95,7 +95,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F where F: AsyncFn, @@ -109,7 +109,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl AsyncFnMut for &mut F where F: AsyncFnMut, @@ -125,7 +125,7 @@ mod impls { } #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] + #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F where F: AsyncFnMut, diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 9b23874bcf7ba..d3fda1cd273f9 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -71,7 +71,7 @@ pub mod rust_2021 { /// The 2024 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "prelude_2024", since = "1.85.0")] pub mod rust_2024 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; @@ -84,7 +84,7 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::convert::{TryFrom, TryInto}; - #[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "prelude_2024", since = "1.85.0")] #[doc(no_inline)] pub use crate::future::{Future, IntoFuture}; } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index a70af793004b2..3d9ad0706eb0b 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1009,7 +1009,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[rustc_diagnostic_item = "ptr_swap"] pub const unsafe fn swap(x: *mut T, y: *mut T) { // Give ourselves some scratch space to work with. @@ -2150,7 +2150,7 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// ``` /// /// [subtype]: https://doc.rust-lang.org/reference/subtyping.html -#[stable(feature = "ptr_fn_addr_eq", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "ptr_fn_addr_eq", since = "1.85.0")] #[inline(always)] #[must_use = "function pointer comparison produces a value"] pub fn fn_addr_eq(f: T, g: U) -> bool { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index d75d570a969f8..5d9d337f101a5 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1594,7 +1594,7 @@ impl *mut T { /// /// [`ptr::swap`]: crate::ptr::swap() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[inline(always)] pub const unsafe fn swap(self, with: *mut T) where diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 1058fa42cc1e3..21bde4b8cc1fb 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -224,7 +224,7 @@ impl NonNull { /// } /// ``` #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_stable(feature = "const_nonnull_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_nonnull_new", since = "1.85.0")] #[inline] pub const fn new(ptr: *mut T) -> Option { if !ptr.is_null() { @@ -1146,7 +1146,7 @@ impl NonNull { /// [`ptr::swap`]: crate::ptr::swap() #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] pub const unsafe fn swap(self, with: NonNull) where T: Sized, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index f800e0d391c9f..8939e5072ba32 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -913,7 +913,7 @@ impl [T] { /// assert!(v == ["a", "b", "e", "d", "c"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_swap", since = "1.85.0")] #[inline] #[track_caller] pub const fn swap(&mut self, a: usize, b: usize) { diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index ba429005fab3d..4c51ca0a5e437 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -60,7 +60,7 @@ impl RawWaker { RawWaker { data, vtable } } - #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "noop_waker", since = "1.85.0")] const NOOP: RawWaker = { const VTABLE: RawWakerVTable = RawWakerVTable::new( // Cloning just returns a new no-op raw waker @@ -564,8 +564,8 @@ impl Waker { /// ``` #[inline] #[must_use] - #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "noop_waker", since = "1.85.0")] + #[rustc_const_stable(feature = "noop_waker", since = "1.85.0")] pub const fn noop() -> &'static Waker { const WAKER: &Waker = &Waker { waker: RawWaker::NOOP }; WAKER diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 56d734ba2fbfb..f7d2eec90743c 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -298,7 +298,7 @@ impl HashMap { #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable( feature = "const_collections_with_hasher", - since = "CURRENT_RUSTC_VERSION" + since = "1.85.0" )] pub const fn with_hasher(hash_builder: S) -> HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index bcf6d6b4ccf3a..c1b794c58f120 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -390,7 +390,7 @@ impl HashSet { #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable( feature = "const_collections_with_hasher", - since = "CURRENT_RUSTC_VERSION" + since = "1.85.0" )] pub const fn with_hasher(hasher: S) -> HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 535236ff89a37..11a29cdae62e2 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -622,7 +622,7 @@ impl Error for JoinPathsError { /// /// In UWP (Universal Windows Platform) targets this function is unimplemented and always returns `None`. /// -/// Before Rust CURRENT_RUSTC_VERSION, this function used to return the value of the 'HOME' environment variable +/// Before Rust 1.85.0, this function used to return the value of the 'HOME' environment variable /// on Windows, which in Cygwin or Mingw environments could return non-standard paths like `/home/you` /// instead of `C:\Users\you`. /// diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 476c403c21f33..38b723366175f 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -339,7 +339,7 @@ pub enum ErrorKind { #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] NotSeekable, /// Filesystem quota or some other kind of quota was exceeded. - #[stable(feature = "io_error_quota_exceeded", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_quota_exceeded", since = "1.85.0")] QuotaExceeded, /// File larger than allowed or supported. /// @@ -364,7 +364,7 @@ pub enum ErrorKind { #[stable(feature = "io_error_a_bit_more", since = "1.83.0")] Deadlock, /// Cross-device or cross-filesystem (hard) link or rename. - #[stable(feature = "io_error_crosses_devices", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_crosses_devices", since = "1.85.0")] CrossesDevices, /// Too many (hard) links to the same filesystem object. /// diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index 22a364074c52d..713e417e0440c 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -13,7 +13,7 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] #[doc(no_inline)] pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 64349987fcfb8..4ec328208f015 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -169,12 +169,12 @@ pub mod rust_2021 { /// The 2024 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "prelude_2024", since = "1.85.0")] pub mod rust_2024 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - #[stable(feature = "prelude_2024", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "prelude_2024", since = "1.85.0")] #[doc(no_inline)] pub use core::prelude::rust_2024::*; } diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index f7e831dc8bd85..c62ca9fd9ad6b 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -134,7 +134,7 @@ As of `2025-01-02T`, the list of known names is as follows: - `unix` - `windows` -> Starting with CURRENT_RUSTC_VERSION, the `test` cfg is consider to be a "userspace" config +> Starting with 1.85.0, the `test` cfg is consider to be a "userspace" config > despite being also set by `rustc` and should be managed by the build-system it-self. Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` From 79b00df93a1170a275e9b1dbc0bc71150c9c7784 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 20:03:28 +0100 Subject: [PATCH 120/189] bump stage0 --- src/stage0 | 912 +++++++++++++++++++++++++++-------------------------- 1 file changed, 462 insertions(+), 450 deletions(-) diff --git a/src/stage0 b/src/stage0 index 23ee3304b4226..bd9a753c21153 100644 --- a/src/stage0 +++ b/src/stage0 @@ -14,456 +14,468 @@ nightly_branch=master # All changes below this comment will be overridden the next time the # tool is executed. -compiler_date=2024-11-27 +compiler_date=2025-01-08 compiler_version=beta -rustfmt_date=2024-11-27 +rustfmt_date=2025-01-08 rustfmt_version=nightly -dist/2024-11-27/rustc-beta-aarch64-apple-darwin.tar.gz=58e2ba5f6a388a5bc9ecfa1c7ec4ba3efd9662e1875ea5fba484c75c5f930227 -dist/2024-11-27/rustc-beta-aarch64-apple-darwin.tar.xz=95f3ed14a6e3093cdee83f80227c7966783fffcc0ff0be6ef095df0dc744b9f8 -dist/2024-11-27/rustc-beta-aarch64-pc-windows-msvc.tar.gz=687b58e25baa685be9357048cc1e0c469c25dc6530db55e0179234615ff4d289 -dist/2024-11-27/rustc-beta-aarch64-pc-windows-msvc.tar.xz=694e2405efb25c53575599ad6573d8c4646a168e5d4bde922ef5e7d43f3e530c -dist/2024-11-27/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=4b42d00e701f90c1fff9a692f1bc1da957fcadbd1813c3066dc1f1990bceadcc -dist/2024-11-27/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=4f83a8cced878c03aea2d6cec7e1d588c2b6590850664f28f3b49a3be3a8b827 -dist/2024-11-27/rustc-beta-aarch64-unknown-linux-musl.tar.gz=bae97ca3778fbaa40f6db4da4f6da0b2bb870e9880165fc3126363f55a1fb23a -dist/2024-11-27/rustc-beta-aarch64-unknown-linux-musl.tar.xz=3e617e866a8c03fef243dede8c086d085a6564aeeb5570bada62db5a16e95f2a -dist/2024-11-27/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=96d2f23814db8286de9ffce7bab033aa4dc656f83aa39418c8f877a5befbb100 -dist/2024-11-27/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=0433a866c4d8a434990746216232759345d3ef556b0b92358b231fc1e727962e -dist/2024-11-27/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=6a776c6eb2b7b4992eed6a127d11b8845695cdc5d23938ced2267f88f8d97033 -dist/2024-11-27/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=2649e0f522755dcd511a6459258c3c3a24808fc49d3513f3d9098b17bd0f2c79 -dist/2024-11-27/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=02a65e970ee930b46c2d10e1eb3d2e6f2420e08bbef039f10a8311baf57f274f -dist/2024-11-27/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=3843610c7ecf98948a5f78a364c223d520a084bc8c49ec0c3c8ec48bad6c0bf8 -dist/2024-11-27/rustc-beta-i686-pc-windows-gnu.tar.gz=75288ca1e65157b8902195ec2fff31015017c90d3b8f51890f2f851529b200cb -dist/2024-11-27/rustc-beta-i686-pc-windows-gnu.tar.xz=5c694e50b41cd6f2c7b59b891eda3e728a1a2c56617b96c9da001b35885637b4 -dist/2024-11-27/rustc-beta-i686-pc-windows-msvc.tar.gz=6d1a66c090322ccf272a425c779f9165398e6bd9e0c7e5d0a5f262086d43ed88 -dist/2024-11-27/rustc-beta-i686-pc-windows-msvc.tar.xz=e826fe8be287f8969d11f620da9d01ea0d913eba145fb79ae86bc78674f1b919 -dist/2024-11-27/rustc-beta-i686-unknown-linux-gnu.tar.gz=31e0d9a1ff97d92c391cc913fd865a0c8afd614279654350d469bdf881a1b1a3 -dist/2024-11-27/rustc-beta-i686-unknown-linux-gnu.tar.xz=3b11a6be4863cb6ad420b66558b7745431834d1fac5dbda899a384dc30b526cf -dist/2024-11-27/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=59d96cd092a56d12ea796b65225479803edadbdcb483effdfa36e191f73483f1 -dist/2024-11-27/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=0714a469cbd7d96118e9260f80fedf34b21234776904e9c8ec5b71c9493dd36a -dist/2024-11-27/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=25113ca9719a036ae581f68df4dda74f1446b49ababe7bb194510fbd1b296e7a -dist/2024-11-27/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=25bd910ea722fe2d4a1e66089352c92f97759ec7212af2b9a04431b469ed8e12 -dist/2024-11-27/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=7a83c9f63d88849c4d691ad1d7fbe7ab5924b5a7d76378ddff5024269be95310 -dist/2024-11-27/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=fbbb11b4c986186d94b0e00ebc70400d0071efc2ba3b802abdd877d86b8cacdd -dist/2024-11-27/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=6223dff24490e3e8506dfbe2b12620155d7c05fce92191cb01f3b28e269bf1be -dist/2024-11-27/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=6fb1edea73bcb76d9cb6061d1aba15ee4655a212c1bf96328a225c7c05df3462 -dist/2024-11-27/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=0b7bc9ec0c40a6203fb62eb71fb6eeab43a4f64a2f7d0d51a1e0d041a216adb1 -dist/2024-11-27/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=d77a49acbf26b8c9a2a5f79fdc640feb1c81b9fa38f442b81f69127f49c7cde7 -dist/2024-11-27/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=bdf45a37fad10df4822690ea73840b38ee3e1048878982e625efbad3b2054f28 -dist/2024-11-27/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=ad6a2f03b2e27711e1ec4eb75502782c4bc0200cfaca2b5246e0bd5b86bf29ad -dist/2024-11-27/rustc-beta-s390x-unknown-linux-gnu.tar.gz=b0cc3024a717d33775dbea63e83f317f8826e564ceb4ecb7a6cf23676f66ccdc -dist/2024-11-27/rustc-beta-s390x-unknown-linux-gnu.tar.xz=9d5b44a82803d5de5355ffced6ec1dcb9860950910bba6dc54878ad4da7ff444 -dist/2024-11-27/rustc-beta-x86_64-apple-darwin.tar.gz=c7174c35b530453182f5f0b15c6684c030a2ff2770f4cc1a4a4ba75695e53b99 -dist/2024-11-27/rustc-beta-x86_64-apple-darwin.tar.xz=c68c26159a3fb4d4380fb25488aa78223989893d7786b8ec947d82ce0cc905bc -dist/2024-11-27/rustc-beta-x86_64-pc-windows-gnu.tar.gz=c97caf7877097d78fe2191e715e3a45d827d28c27b4dabf0747f8ca522ee43f5 -dist/2024-11-27/rustc-beta-x86_64-pc-windows-gnu.tar.xz=b7794ecabc42698cb77c1c90d66676a8b1b3632108ab95954ee496ee7d6e5708 -dist/2024-11-27/rustc-beta-x86_64-pc-windows-msvc.tar.gz=28068a6e050abe21933920dba3ead2261f7d0c09687d5a86a5db51cca6e72ea9 -dist/2024-11-27/rustc-beta-x86_64-pc-windows-msvc.tar.xz=3860d7ec8564019c79551727a3a54c66453a7d654fbb89b8feeae75d9021fa77 -dist/2024-11-27/rustc-beta-x86_64-unknown-freebsd.tar.gz=6c2a918f8d40ba01e648565c98ea120d32562dd93820e8f2e33abb2aef08e1da -dist/2024-11-27/rustc-beta-x86_64-unknown-freebsd.tar.xz=5d1edcc6c4be49849c3c2d1c3c173d4a127db3cfb615093e5ee396e0d0c77366 -dist/2024-11-27/rustc-beta-x86_64-unknown-illumos.tar.gz=a64c30d82dca58d09bfa38e72bbe1457b48b101157193a3ee33dd85922bbfe9d -dist/2024-11-27/rustc-beta-x86_64-unknown-illumos.tar.xz=87d14b146386fe1f9e24fedc25e1bf9682913bbd7537047b0baef0d74cad5473 -dist/2024-11-27/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=3f186913535ac59446e249f4d3e35e3d93a3f8207b31ee31b3f70af8344856bc -dist/2024-11-27/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=0c17a60ebac74a9cdfc2ec69fd71a21e370ff178f4c83be6020642b55b6d78ab -dist/2024-11-27/rustc-beta-x86_64-unknown-linux-musl.tar.gz=327973698dd0ffe9b2d56b3b5929f82ec552f2002b4113fc9a738e27b0005ac0 -dist/2024-11-27/rustc-beta-x86_64-unknown-linux-musl.tar.xz=d7e2f768922ae36a9eb302667398ee308c13f829c03235682529fce90253813d -dist/2024-11-27/rustc-beta-x86_64-unknown-netbsd.tar.gz=13f327974170a0423ea6e7241cd3a454ab8c39b657a707c08f2e306a7a657b45 -dist/2024-11-27/rustc-beta-x86_64-unknown-netbsd.tar.xz=5c75388802c0ddcfa51336883f4039b6f7963e0efbe47c209bb455c12951990b -dist/2024-11-27/rust-std-beta-aarch64-apple-darwin.tar.gz=84c4c02fdecc669c5d26c49120fdece5899133c098f5ef791ea19aba33936dea -dist/2024-11-27/rust-std-beta-aarch64-apple-darwin.tar.xz=7ea047840073e6ad3123a61ca799bc56c951edbb71cb8495ecbc2029759a0190 -dist/2024-11-27/rust-std-beta-aarch64-apple-ios.tar.gz=dfb8207b4b3bc13a9704fd1d212d92a22a0e7a57293f24f28bcaa846ad4c08b6 -dist/2024-11-27/rust-std-beta-aarch64-apple-ios.tar.xz=96940a84d95b4cfdde84a501758c9dd83f5d6cb5afce9142917d5cb3dd75c040 -dist/2024-11-27/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=4ed66daf59e9a8b61d66caef4b2248be72049282518d7526be771301bee2b905 -dist/2024-11-27/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=013d59e32097917b269c45a837bff380a41c4f6401b0c145264cca5a1bbd91c3 -dist/2024-11-27/rust-std-beta-aarch64-apple-ios-sim.tar.gz=270a0322dd3c2342745faa8797f4f64da8c0028b322385d209ff65cf04965a47 -dist/2024-11-27/rust-std-beta-aarch64-apple-ios-sim.tar.xz=9d54f7f51c99f17ba9cfe7cbe005ddbfe598f8af6df1dfccc9ef37029cc08b41 -dist/2024-11-27/rust-std-beta-aarch64-linux-android.tar.gz=9ae4c1d6044b2c3586791f127108e308e0a381e8e14ecc20b3830ae5258a03c2 -dist/2024-11-27/rust-std-beta-aarch64-linux-android.tar.xz=689225ea098a88a88e8e2269ef53f964405a6c31b3ee2bda0fef98da4ed9178e -dist/2024-11-27/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=f1d9c996cbe468ca93b15c76b84c544930d7452f1eff2968a298c885203f14cb -dist/2024-11-27/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=f3f8c088d74c81b2457ddff57008cb908cc86e16d0fac60d10969e45210d88d6 -dist/2024-11-27/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=fb4e5d66911a47bd63429686885cd5c7f0a6310b25622f36bb43a754300526be -dist/2024-11-27/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=ab6c7d346bfd72f06fbbc198743bda35fcb7fd1e131c05c54935b6ceff282f17 -dist/2024-11-27/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=32b2e0d5161f7d8354d846c91e5cb25530e78351dfcff4ebf0a6fba669e2c483 -dist/2024-11-27/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=656fc4a8af570b28b3f83cd59d4e5226f15d11b5d8c26b58ca2c1b2a4e18c4df -dist/2024-11-27/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=13c98efcde78c1e187f728509f2950a0a407ba32e730877cb9ca4cbb4ba01469 -dist/2024-11-27/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=6372891715046375fd0a04e80c95bf79080db2d136e187b02ea96647e9281407 -dist/2024-11-27/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=db156e0d5db6f04621e625e92323a04091c049a8b5e2b4f7e0fb2e50b81ab2ec -dist/2024-11-27/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=b610214bb59b8f58be96b84b0f13e5f50473e21039f6e827fa16c446d0e9ccba -dist/2024-11-27/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=99f96b0bda31bf21853c96b3618408587f275f46ea9bd7d1fc741e58343a5625 -dist/2024-11-27/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=dfa1f209f546b457aa6ef742a645f00f55c70fde86522c737f7a560494170157 -dist/2024-11-27/rust-std-beta-aarch64-unknown-none.tar.gz=4735b29991a2337a7e2016c5a827635e17ac149372efafc0442a86b0dc0759fb -dist/2024-11-27/rust-std-beta-aarch64-unknown-none.tar.xz=fead0635c572aa4f5e5564e497f1b7e892217ebe52fea54aedacbefb32f6343d -dist/2024-11-27/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=bbb9b6fedb874a61d99d22b4cdb2d20d8b9e6c69924922312692aa526851b960 -dist/2024-11-27/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=9e0d48236676dc9947565daf0c2605316c5b4abc06bdb1c343559c46b9c4e304 -dist/2024-11-27/rust-std-beta-aarch64-unknown-uefi.tar.gz=e230ffa3d46dbe5330416cdf8b7235b8dc2cf119ef8990b422eeebd017ebd17f -dist/2024-11-27/rust-std-beta-aarch64-unknown-uefi.tar.xz=38a5560575740f92cb8664d204924cf7a2972e0f2f396852d8a22befd2cdd848 -dist/2024-11-27/rust-std-beta-arm-linux-androideabi.tar.gz=0b0a9f95d10484207c52fcd8ab1bd56903b53f18ce46fe263d5b7bb085044246 -dist/2024-11-27/rust-std-beta-arm-linux-androideabi.tar.xz=91f7655ab2bce397a0821edc0f523dbf2bac0af39a50ead106eb1de637ec5c44 -dist/2024-11-27/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=e8210f03bc18661954f147dedd0b4af721d005866c0c4fea1e91594cd6c9bc2b -dist/2024-11-27/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=56a623817e6a600e802727d59d4cd653e84cb628695e39ecb23ae99065113115 -dist/2024-11-27/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=310a408bde58335d8011af480d4f8c38745865772d71631596cef1a79f9f4fc2 -dist/2024-11-27/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=fd6766ea9e828adc2e43ff1654a459785eed05ad00c7f6804c742ff8ae8f6b8a -dist/2024-11-27/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=e663e30526d85d89f41456a3d5bcd411397cb69e7cb9508aa1472b015963fd18 -dist/2024-11-27/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0361504ada464a7d21e7ac66fdf9e1e820695f3a8ca4854695e78a748c5c7a18 -dist/2024-11-27/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=c375be97e626900d809390c61bf6f2d689c9fca8e58c85e4e02b694bed4c5ce0 -dist/2024-11-27/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=c33e3b4f9098860f75fcc9a8f86c7e7173692ad4c19cbb2c0de068961f87c192 -dist/2024-11-27/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=3f50d9afd9df4db85958e4575429dd4c80b6702a8d91c3f1d9327345aaadefe0 -dist/2024-11-27/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=0016d3a6ec8351ee9fac2eeae358a0854a3c2b360822bb3ba670255e8f27f57e -dist/2024-11-27/rust-std-beta-armebv7r-none-eabi.tar.gz=f23117b972ccd21c0a6f4db4b544401045c9f157595a297fb56d7e864cf190fe -dist/2024-11-27/rust-std-beta-armebv7r-none-eabi.tar.xz=ab9be4bb25b1575af276cbec7fb1a1f8c683741b0f137bca7b4b61ab13575645 -dist/2024-11-27/rust-std-beta-armebv7r-none-eabihf.tar.gz=673561456e26bc992cb6a888c34c0b6b13e1bd0d3e0764360a785a6c3369f0d0 -dist/2024-11-27/rust-std-beta-armebv7r-none-eabihf.tar.xz=29c6f01c636bcd901b88e92c60874c454369efd41f690d74b1fa2adf3450166a -dist/2024-11-27/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=c214d4439676a19c057324dc736d63aa0328ac74c0eb9ced8d782d8bc89757ae -dist/2024-11-27/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=4baf85ac632750c35d007bcae8f23720208c5197f4a1d49b0a85b2b0e137f603 -dist/2024-11-27/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=a7e81c0e80f2508c81ba9d8e658dabeb19af2de6f7365f6e377d39e99d8449e7 -dist/2024-11-27/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=3f37f746aaa03107573a3a2b201c15bf86777ec405dc03640e7d3f24f718f67f -dist/2024-11-27/rust-std-beta-armv7-linux-androideabi.tar.gz=fe7c7ecb8a8e612caf0e7ecf04d18ccaed31d8b93911ded6b3cba0c78fcbbddc -dist/2024-11-27/rust-std-beta-armv7-linux-androideabi.tar.xz=d571b714821de4b7d2accad221b5e043e7f9aead8dbc06586f4f7ff3f3f3e38e -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=663396f0e4c45bfc041b1a502b64627620f499ca6343664633761c3fb1c2229e -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=4d8c47d74958e3b1058ab721e9c6635774afad0252f251b0c9fe4f0895d0c81e -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=3cba82809bc1204b6e8f62877c5e9f9a08f111da7d439032cc30d55be0e88fd7 -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=d525a4dde496e72fd18c6f2a525756d652ced436007f513267e9201d8b1c0a40 -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=ec0311a0722f205b117160817b2137e9a73f0f4e540930d61c831ceba1265f0d -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=c63c4a28225dfca26baab129f06d8537fae5710083046f203a2fb73c50b48671 -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=52eae1bdf37366bf406cff95e5e7979d0651979ae5ad4c036e8badddc8ec8b82 -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=542791fb5cd80fe5515ab0812c9fd8671f083151d4262fc76d26f7723ba961e1 -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=91697f75c762bdb51f19348953768a45bc37c389c2e904a56f4f092604ed2d1c -dist/2024-11-27/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=a79a7a5974b365f70598c413da3db8262d14414e3b4d48dde45f529bca4c6ef8 -dist/2024-11-27/rust-std-beta-armv7a-none-eabi.tar.gz=6eec497ec2aaf6c5beb8e6dfbeaf32190b6f7206aebffb7499b5fdd7e5e7643a -dist/2024-11-27/rust-std-beta-armv7a-none-eabi.tar.xz=234924a6746fed2efa112b0b805d0ca56252b6cde82e6422774871e9c009fed6 -dist/2024-11-27/rust-std-beta-armv7r-none-eabi.tar.gz=1b0cd107412fae22266267bd8eccd2b39a36afa8936da3888d0bd0d2f4cfdb1c -dist/2024-11-27/rust-std-beta-armv7r-none-eabi.tar.xz=0d0d1ee48f9032df88ea7b3f73f06300686f4d5b9fc16f1d4554caf8356cfd74 -dist/2024-11-27/rust-std-beta-armv7r-none-eabihf.tar.gz=72f0549de44925bd08286e092261164dac47826124123e3fe707411a3dfa756c -dist/2024-11-27/rust-std-beta-armv7r-none-eabihf.tar.xz=eb45acd55dd70be3670de83c8cbef5b6ef05827b3f97b7c71679a19c88f8f3e6 -dist/2024-11-27/rust-std-beta-i586-pc-windows-msvc.tar.gz=edd8dadbba618f2a786dfcc68e4a5c7f2b7cf1528d1c16ca6ddbc52622df95c6 -dist/2024-11-27/rust-std-beta-i586-pc-windows-msvc.tar.xz=ae59c5d77b31aeac30c22104abc0abda6b7f725419e9f86db6cae634ededf262 -dist/2024-11-27/rust-std-beta-i586-unknown-linux-gnu.tar.gz=8996c94269e4c60270d253ea75bddb9482facc441ee2314a387888924bea1d92 -dist/2024-11-27/rust-std-beta-i586-unknown-linux-gnu.tar.xz=f6b59e3d6e7f0e458c048ad4aad9a2da23f3b54aeac20a905d2e00379da1bd6a -dist/2024-11-27/rust-std-beta-i586-unknown-linux-musl.tar.gz=85f22b148be72691214dee620eac582405dc3b8937d2ef7c480c9070b963af3a -dist/2024-11-27/rust-std-beta-i586-unknown-linux-musl.tar.xz=4b48538541dd20fad8569cb3f0994d5ce6aceaacdd8b319d00b0234cefc5c267 -dist/2024-11-27/rust-std-beta-i686-linux-android.tar.gz=6e5ce19fc4cd8cf4dbaca8b31f4032b08ee413ce20f354186e4945efd4e8b6af -dist/2024-11-27/rust-std-beta-i686-linux-android.tar.xz=5e78b98abdf2b7348381863052c109beec025a5f68285ce72e6f6e9245c22ce3 -dist/2024-11-27/rust-std-beta-i686-pc-windows-gnu.tar.gz=50057f990d1127e7d693b1c5b9539b19262a478130bed51dbc2837d61d2db6da -dist/2024-11-27/rust-std-beta-i686-pc-windows-gnu.tar.xz=ea524b276e42a1cb918625df12b8d3397ada5ecd43bb9ad5c676747e1f916c8b -dist/2024-11-27/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=c7c9093e277187590b86ea02fcd940071c8bce93a894396d73953276ec58eb1d -dist/2024-11-27/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=a67879ff0dcc591d30a155fd972149953eaac3b139bec9aca3a383dc277ddbc6 -dist/2024-11-27/rust-std-beta-i686-pc-windows-msvc.tar.gz=a086c8272f9c7c0db3d5de37b027478dfc22fc577c613254a821700c645df3c9 -dist/2024-11-27/rust-std-beta-i686-pc-windows-msvc.tar.xz=8ac4b938e0b643e47d6d0ba6e5283887fcc73cb1a825fc065c35879b085d9c28 -dist/2024-11-27/rust-std-beta-i686-unknown-freebsd.tar.gz=3614b95b54ca24c598e3ed6e14aaa86f7048c2a5be2b3e9f97d9ca00f3d890ce -dist/2024-11-27/rust-std-beta-i686-unknown-freebsd.tar.xz=6d36127f5c113b01300fa0d54062bc1137b51d2514346c8d84bafb9f2c56a972 -dist/2024-11-27/rust-std-beta-i686-unknown-linux-gnu.tar.gz=a6d33a96eeb667f3f4649ea6ccdd6212a183bce85f095ff7db5036c3a50d35a6 -dist/2024-11-27/rust-std-beta-i686-unknown-linux-gnu.tar.xz=bab1dada484d61bb96e2834da5fc6ed5d4d788e6636849e9802f9fb6bff45d55 -dist/2024-11-27/rust-std-beta-i686-unknown-linux-musl.tar.gz=0ac331a1c9e384430a5f316809bffdf01bae3ae9cc1f807f07142ffde7388602 -dist/2024-11-27/rust-std-beta-i686-unknown-linux-musl.tar.xz=136341bbf4c820dfc98e96cee41fa0e9fcbc7d81d2772407efaf1d4be6d10f7f -dist/2024-11-27/rust-std-beta-i686-unknown-uefi.tar.gz=32f06ca3b2752a8687e2f282a59823671fcec672bffc0775a9fb27da50b6bb11 -dist/2024-11-27/rust-std-beta-i686-unknown-uefi.tar.xz=b2f376089b39a34f3308833ce9bf65200f9665e5c55bbda3e5b7e9c5096b7e67 -dist/2024-11-27/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=a2ca950893c93be71c7db707230b98674a29c013546e27d95bdf8c3c6eebf9a7 -dist/2024-11-27/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=c70b58f4583578347e9f0fa20d17bd5fc51d88717095e05d73091209f2a363be -dist/2024-11-27/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=ed284c40b6253c022e39718dc2af2e4100ca7e805d35d86aca04937586f26ece -dist/2024-11-27/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=3efcabf46e0d02505ebf0926c6c14e0c70838f9b510f2328ccd98dd0fa977794 -dist/2024-11-27/rust-std-beta-loongarch64-unknown-none.tar.gz=9b9f8418fdf64fef652f15b28a1a1f2f8c63c18da8b323994f10f921010721ab -dist/2024-11-27/rust-std-beta-loongarch64-unknown-none.tar.xz=fdc673e4b250424c6dafc18a165ffb592aecd7b897e483af8ca54aa145a0e6a9 -dist/2024-11-27/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=802d22c1c364a58402f9313c6ba2f58b79f3cf3163842a608b78680fa2b3d476 -dist/2024-11-27/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=dc4932d91d8a2887d309dbd6317d6c41afd083043f44742138ca7c97f60b931c -dist/2024-11-27/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=636b19ca036fc7ddcf358062c98f6bcf31e8c2cd035cbb9dc0a6b96c81217f7c -dist/2024-11-27/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=31f80fc50be95bf665d21fe52b714532ff34ebfcdc0c975bb68f7d2f2cebd0e0 -dist/2024-11-27/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=f2c83275df652bc5b387525e77a1aa30bac31fb301b304ddd7e6bf402e140c34 -dist/2024-11-27/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=41358bdb20fe3a97a95fd7b656b1ed03d5b8012354d8cfad2437bc9ef6c7aeb6 -dist/2024-11-27/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=49b8f286b4abb3b34bd38c92ea3e15efbd1f623d5efa7bcff10711b595363579 -dist/2024-11-27/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=283f065701c77fa47a2d5413d20fa40989fbbcc75bc938889de6c4f9b6b9e53e -dist/2024-11-27/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=d0ee5ba5dd6f94dc6ca981be0d55f2e3f51c2af25877131a7a74e0ab9848dc3d -dist/2024-11-27/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=79c78bb31022ec8e7a3fad9823c5d22ac553d389104844110473d1877d8c8302 -dist/2024-11-27/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=b953686e3034f2b51033a2630328c8eb5f59fdf8ef4e26189bddb8efb4c482cf -dist/2024-11-27/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=fb25ac2e68594d379f915f0555b3ded2b1a7b5a67144e12eb62949f540b0d957 -dist/2024-11-27/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=fbf5a16a57de3a7e846389aebe18bc7871f43e67eff39fc9b4744b5a445b2639 -dist/2024-11-27/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=55a92aa5770924a21b706724c15f58d66ef2ca5b630f7025f6ba1416152ef350 -dist/2024-11-27/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=b880b7209ea604761ad2a46832925d32fc547737b879645fd3cf99ec235e7b39 -dist/2024-11-27/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=c48cc6a6fda06fab014c0b8fef49006dd32fb71f8e981ba44a0c25d47fbfe034 -dist/2024-11-27/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=7d133b6c8d0e8b8ec8b65a74ed8d64a22e2fa5e4f6d4a1e36f9e0ebb8826f40e -dist/2024-11-27/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=1c507e003c38115bfffe8701df1ff7aed6ad16ef5ac4b383f84bd2d6aa0216bd -dist/2024-11-27/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=111a909b3d1a04b328ca1c1f247ee4eaaa84349eeaa8df77f7901bbc0efc94c1 -dist/2024-11-27/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=d29f92ed071c60259feaa8005eb5392da549f8e2069fecb1b77e112f89cf1bbc -dist/2024-11-27/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=241b1ec9ef6a89277944c9d8021f521284dc28822c5f80513b6cd94d2bdd1d64 -dist/2024-11-27/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=9f5b02be846fa2084becc5616f024094d47beca102442ac7a0e3588e0f12ee7e -dist/2024-11-27/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7272eae1625415c0f57bf541dd62c14e02b9946ca1de04615827a1f5218c2181 -dist/2024-11-27/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=d4bcd0068d3c9e7351565fec57ca68d36c9ddbfe59249a6bd2c56930ebad2257 -dist/2024-11-27/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=758ccc47004398add2e3cfef52e4839e14dc4d132a215658e576e590401a28ca -dist/2024-11-27/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=6902fee1027b0136f8dc5179e69e24ed9e34366e9409129b9ba223043ddadea1 -dist/2024-11-27/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=3024570f3e382a57fce0e832c52d080a83d42206d8412b724361bd1f0087ec4d -dist/2024-11-27/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=20eaa72b6fa32b9884b43030a0bee554bafa9de3f3b51c5768ba0ff47ec492c1 -dist/2024-11-27/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=a3eae70be3fa5b0a56cc88cc6433cdb7c42b3b974caf0d879d21a5219f4f826e -dist/2024-11-27/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=1da88d1882d4dd1f15ca97e016f392a01b56951882ae75929023e83fa557d796 -dist/2024-11-27/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=387cc8ccaeed6f9c6a8c9d21004e45ac97a9739643a63448eb893e13ed4df22d -dist/2024-11-27/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=1b9afe3631fb7847b2a8a8f483fc00ca203ccc18ae298339801dab1c7b06b3b3 -dist/2024-11-27/rust-std-beta-sparcv9-sun-solaris.tar.gz=f9a4d2115d6fce06e0da7a9f579b197d383034c218573e145b3c7dae0aad21d4 -dist/2024-11-27/rust-std-beta-sparcv9-sun-solaris.tar.xz=c352bc631e538d4e68eaaccdfb9dca1c9dc8ff0ef4a75d8ee91016aada39d717 -dist/2024-11-27/rust-std-beta-thumbv6m-none-eabi.tar.gz=d97851ca9193d98192a55aeaf695973ac706e6ba3e198643c200cf410817b424 -dist/2024-11-27/rust-std-beta-thumbv6m-none-eabi.tar.xz=89a6524a3743e5a769a583b4a6bf8a76ef5b45c67b7e39da7ae24b687bed4943 -dist/2024-11-27/rust-std-beta-thumbv7em-none-eabi.tar.gz=6fe614db166618a8f2ccb5807e02884daa8bd8dfded2164f88d79fc688047020 -dist/2024-11-27/rust-std-beta-thumbv7em-none-eabi.tar.xz=91c5e4f4575ab004119797988679077e5057881ad9a7f6790b673dd062a8b7ee -dist/2024-11-27/rust-std-beta-thumbv7em-none-eabihf.tar.gz=d0e05467fb1562ed7d6687a50b7fafa14ba0c2aad328f0e7c19eaca1ee366475 -dist/2024-11-27/rust-std-beta-thumbv7em-none-eabihf.tar.xz=0473372df5fece49e58efcd3b2a702bb93e47ec149b38fd5244ad667804e7c63 -dist/2024-11-27/rust-std-beta-thumbv7m-none-eabi.tar.gz=e6b6130a1a571325cc1bda8ddba6b2672104c2feeed5c93c6022bfcc8ba4b247 -dist/2024-11-27/rust-std-beta-thumbv7m-none-eabi.tar.xz=d4c739c42104e04aba55b96a3ad434e11b013ba44649dd3a648cfbb15de83eb9 -dist/2024-11-27/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=e427d5d6a53abfb53b436df96457d58eedc648198fce6b1d976b50de18cbc31a -dist/2024-11-27/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=11142018c11849c21adaa7096abf50d0c923f3b8f07d67eb96d6860d428e9b27 -dist/2024-11-27/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=46596d8f2271dd5a6f0f84387ac19d0e81976adfc6050b6aab6cc554102fe469 -dist/2024-11-27/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=f3d0c9db1c50a018540278433fed2e0ae4bc798aa0dac87cf0f55ad1808618a1 -dist/2024-11-27/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=c46fc4bf174fc54f5565fa04e80efff4e853642e3e5f0bf5b696a2bd6e7ae817 -dist/2024-11-27/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=706c10ef22cc16b3d4cab8fc09d8783384313b9f774229470b8ae1dd292850b2 -dist/2024-11-27/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=b9cec80ed374f7b5f22f1446e3f2e0dacfaa0e2d4d6c631ad66cc42a23e156f7 -dist/2024-11-27/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=41c67ee95e72a3d10bdf739c4841bd937c4e0b19c33451724c1f603b4bd2a318 -dist/2024-11-27/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=5ad8603f98cff0d5d015c72f3a55730d75d59680a867c067928bf4586c00d805 -dist/2024-11-27/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=61a75701f7e000f86f318a04dc6746f029fb933e0ea94944d76c7eefca1f24b2 -dist/2024-11-27/rust-std-beta-wasm32-unknown-emscripten.tar.gz=89bfbfea23974ed75a53ff134386992e9c257d3e51a55eb49847aec9c5ba6b13 -dist/2024-11-27/rust-std-beta-wasm32-unknown-emscripten.tar.xz=e34d1586bc6767b4b244f98754badda706645fdec7168ddc0a409b9f95f2b18d -dist/2024-11-27/rust-std-beta-wasm32-unknown-unknown.tar.gz=8a88bb923e138d0015c8f46bc1c3d5f2f5f75f40dddfca72a49eed42c080d1db -dist/2024-11-27/rust-std-beta-wasm32-unknown-unknown.tar.xz=79a980f2b999c3e3b04d7e327bd2b548007039b45da705847c6da2bfec3ffc04 -dist/2024-11-27/rust-std-beta-wasm32-wasip1.tar.gz=454e2c4b46b4684e591c6e4c0f1ce8e3c44623a29d561be3a481ae008072dbd5 -dist/2024-11-27/rust-std-beta-wasm32-wasip1.tar.xz=4dcf652ab51fe03c4691de46365218dc483cf1f7c2f5a552a38509685a0ca873 -dist/2024-11-27/rust-std-beta-wasm32-wasip1-threads.tar.gz=c2c34d9b3998633cfa145dc2a5568a99d1fe26b91c5be55a08870a1d27db4af7 -dist/2024-11-27/rust-std-beta-wasm32-wasip1-threads.tar.xz=4d5b25e4b5fb71d879f15f320f7513eec1ad078d3ca6f525ebf56b9620bdb5ad -dist/2024-11-27/rust-std-beta-wasm32-wasip2.tar.gz=e1385a340d3d9a4003cc456156bfbb1435a5255b2bdae3a40b6d7339768bdc81 -dist/2024-11-27/rust-std-beta-wasm32-wasip2.tar.xz=245e7914174d213ddbb550b09fff200f419bcd632de98548a470013891666410 -dist/2024-11-27/rust-std-beta-wasm32v1-none.tar.gz=d5d924ea001f914bf87df8765b013db6e838a930a4865e95f8d35bfaa86bc81e -dist/2024-11-27/rust-std-beta-wasm32v1-none.tar.xz=bb98d0d55f38f2308bf99d4e5f11842683452571075eefa5b4e1f18f2bd553bf -dist/2024-11-27/rust-std-beta-x86_64-apple-darwin.tar.gz=edd5e7ea230a13be750dd74c5f7a7dee20db8683f7978aeb352307a0ce110b9d -dist/2024-11-27/rust-std-beta-x86_64-apple-darwin.tar.xz=c6cec9a501d9873e3c7abdefd5b9418f7250c8cb915be8b816cb48dedf1f201e -dist/2024-11-27/rust-std-beta-x86_64-apple-ios.tar.gz=e970c2a4ebfb69219dc66e4c7541cf22c52da5f94983c7c914df1f93beda3d31 -dist/2024-11-27/rust-std-beta-x86_64-apple-ios.tar.xz=594ae9bf5f1501322d986dc91249a48a61c22371513b872fd63e134097ac55ca -dist/2024-11-27/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=d57bf579b4629417dbe1c02506db4a4ba4428871a2684141d21303e6c99551f5 -dist/2024-11-27/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=714db83e7563a5f286fb37bc629b64834a9ed981bb9a05931122072f95e39bf8 -dist/2024-11-27/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=feafcba9c46ba3e5fa0bd9b5bedc05ef3423c9962dc4d25a7b2367e3e1caa679 -dist/2024-11-27/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=78fbc8f45df64dca21da7223b5d081111922f2268fcc4f1f83595d159d310bce -dist/2024-11-27/rust-std-beta-x86_64-linux-android.tar.gz=74fb57da7f2907afbaa2a7a73847273ef81e2d6902a326f1ae87767677a864d3 -dist/2024-11-27/rust-std-beta-x86_64-linux-android.tar.xz=3216eb73d9c9effcd2a2de7f63d78055c3d7e50fb8141e2910a45a36ce744ffb -dist/2024-11-27/rust-std-beta-x86_64-pc-solaris.tar.gz=3df431c8941ac28906c3a6568d3debe478d9349d868ea8bd3ad79e65792c20e8 -dist/2024-11-27/rust-std-beta-x86_64-pc-solaris.tar.xz=548c2a6104148bf0da21bf5e009b80522fd15539077a62021a64f16282815a5e -dist/2024-11-27/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=235228431d67feb4c8e6aad44e20bf68574f335e8f948808b597ae98d827171d -dist/2024-11-27/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=5a2d4ed70aed26f902cf45e1dcabc5f25884cf6e9aaff775405ba9c1f0a5cacd -dist/2024-11-27/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=818131158e8be6af4b762750f7927c4a799346c94059a6073230da79b4408720 -dist/2024-11-27/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=fc08b39833e2c9319dcb55cef5c6d1f0110aea794c9a6f163ca39749a22a94b9 -dist/2024-11-27/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=6164c3ade38c03113193301b815c52df0ee84a4ca1c8ef21e1a56d386e28df00 -dist/2024-11-27/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=0846126e6c4cf2b5184979b6025fbb7bddb5c22905bc7ba31fff69f6b1459280 -dist/2024-11-27/rust-std-beta-x86_64-unknown-freebsd.tar.gz=ae308e29be13a176b26c142347a81facf8c11ef1a28e67d5898f4f2a0d3344ca -dist/2024-11-27/rust-std-beta-x86_64-unknown-freebsd.tar.xz=e80bcba8b011a4dd3f7b2a2cea69b5a95ae2cde9b2d9078ac8fdd492ac162139 -dist/2024-11-27/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=b25f0d605b7f4a2a93adb746e32f59bfc26af569a4169e9fb203cb33751d1575 -dist/2024-11-27/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=010f35236062a651b1b54d7c928068efca8dc486856b84b04e98f4f97583bf32 -dist/2024-11-27/rust-std-beta-x86_64-unknown-illumos.tar.gz=db3d258c2caea73b469feb9c11fbd3bcc29d22c3969c406321d11f05c24974ed -dist/2024-11-27/rust-std-beta-x86_64-unknown-illumos.tar.xz=a952b0c2bbed9085525c041c957f00b6b1020e031149dba70c09a1a0d40db3ad -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=817d3d3a931eba2255bd5721435cba7604fe37a72c18a179c1fd5f06dc3b97a1 -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=170a54aa50f161576d4b0d103f2ab6dcbbb81ee57a5a47f7fbd181128f6c17ff -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=ea991dce55415ed7462abbeb1ac1c70795cb628b0460e14230e8cecd41117fca -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=a8f620c3a641f8f4c29d88e4cc54d7637aeb18cf8eaed8571ce558835f742601 -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=875e2e3309b1deccc1a4476e4847a2849df32e0e2a394e4ddf3b4abd1feca534 -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=23f21ac664b3341771109ac69d094518a512391b86219ffec50725dc68a08504 -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=680f5b2c63f58643bd34f9921e2c1699a549410ab06bfd04ce991907e8fd7d8f -dist/2024-11-27/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=dd10f6f3ce39489b6e3f3f638573e850c36518e3b2e8ffad0c50c3143e3a8124 -dist/2024-11-27/rust-std-beta-x86_64-unknown-netbsd.tar.gz=fd31ba490f0bfc53530e34e6e5ab35a52eebee616efc8ed18d473065ea885230 -dist/2024-11-27/rust-std-beta-x86_64-unknown-netbsd.tar.xz=daffc01050f5cf0b5ece91717d7a4c42cd4a148c4c11f641b494d9c375df5177 -dist/2024-11-27/rust-std-beta-x86_64-unknown-none.tar.gz=376d571641a9f1f75fadf951da91bb73ba94a5495d7d33389f5f914ccbec57bb -dist/2024-11-27/rust-std-beta-x86_64-unknown-none.tar.xz=ffd9e826537dc94c6d8e767ef5a61d1fcf0385b8ccbe508ff9177de0fe772939 -dist/2024-11-27/rust-std-beta-x86_64-unknown-redox.tar.gz=447e434b5e40f7882d7adb6d0346629e0e3e92d0f339c7781e5a437898a84b4a -dist/2024-11-27/rust-std-beta-x86_64-unknown-redox.tar.xz=bc21caabcb492ca648e19a8f3b9dc1a1bf7792135a202831deb554ec3ea11077 -dist/2024-11-27/rust-std-beta-x86_64-unknown-uefi.tar.gz=40ca7d9ebcf6610c26f2921c0560729e708f5661bf6167266e9d8cb3987ad0b3 -dist/2024-11-27/rust-std-beta-x86_64-unknown-uefi.tar.xz=06966d5901f5d9accadb47c4d1e561f3f95bd050f3f8e78f30000389f39e9b6c -dist/2024-11-27/cargo-beta-aarch64-apple-darwin.tar.gz=e1a24f081ddd93b483c0f1c196bae676163db50fef0a994bc47c2a7c98c9dfa7 -dist/2024-11-27/cargo-beta-aarch64-apple-darwin.tar.xz=d51a5f0669906eceeee4e09b079828e2ebf3404aaedf1fb20745339205270ee0 -dist/2024-11-27/cargo-beta-aarch64-pc-windows-msvc.tar.gz=e135a5f0f83432b58d9e093c6d560b021a133707e39e1ded90a28a9967105e0f -dist/2024-11-27/cargo-beta-aarch64-pc-windows-msvc.tar.xz=1fbe65015cb8c7ab0b863ffc6f7aa72d3bf52f7830957ede8915c61a22e5b993 -dist/2024-11-27/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=9d4e830e9ba582302865fcefe31883cef4a471e77d46e70838e549ca11a0fbce -dist/2024-11-27/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=233f6347a36e806dcf27ecad4906c90bb3353051f440a819989efcf091cb78b8 -dist/2024-11-27/cargo-beta-aarch64-unknown-linux-musl.tar.gz=6cd719a7255a0eb1f11592b9a92d0aa4986363f624ee0d6077fcc253acab66a8 -dist/2024-11-27/cargo-beta-aarch64-unknown-linux-musl.tar.xz=b874ca8285ad1936adc70a9323cf80f06322b1e6d5925f54b58500129830f0ca -dist/2024-11-27/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=ec7200319224ccabe814cb051e51d147f1ae8c763413002fd03c9263a02c2320 -dist/2024-11-27/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=86e96c80a91862e59123272c80f1cfabdca56bfddcd66af4a5e840af7421c4e1 -dist/2024-11-27/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=3f7cfdcb28fe8c3f0dde58c24a0c424652b40d00a24fc50891351fa5bff5c15e -dist/2024-11-27/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=2d5a184b0103ac943ec4f6756fbc7126773e739e0d120acea7b3244c7cd19b1b -dist/2024-11-27/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=9a77540943f28584d90b4bcae4e234cc9d833eb732f65d7fbd680a0f4e915da4 -dist/2024-11-27/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=7696a065951b7d7179b30ff2fd16a05675b6bd4250f293666b98ec05299113a5 -dist/2024-11-27/cargo-beta-i686-pc-windows-gnu.tar.gz=eaff75076ad71a4291af5465dedf0fb0998dc171e35ab8f707ac63b43e89c38a -dist/2024-11-27/cargo-beta-i686-pc-windows-gnu.tar.xz=205d3d19726a1a87a1533d94f77b73ed9de8181906acb48088dca22835aa7a83 -dist/2024-11-27/cargo-beta-i686-pc-windows-msvc.tar.gz=58da319889533ff7be5c9142c2abdd1ade79de10eb83d7ef82ebd93b75607f8b -dist/2024-11-27/cargo-beta-i686-pc-windows-msvc.tar.xz=5ae699d0f6b9e210a988af5b8f2f0c4d62fb1695ed6fa55718fdf05298039b9c -dist/2024-11-27/cargo-beta-i686-unknown-linux-gnu.tar.gz=362f6338ea929ceb632307031e049dee1b3ed998f5cf160654c327c5e0e7ed39 -dist/2024-11-27/cargo-beta-i686-unknown-linux-gnu.tar.xz=88f14ca7b5c8af006f3c54749b61747485f7e93fde4c65b5969e73503d12c5c2 -dist/2024-11-27/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=9ee8f29e3e715cd7c85e679fd01ca724a27503a50edb0e6f8912f289630bc7a5 -dist/2024-11-27/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=4c643f0d18ba101c2b248e1df32ec3ddba82efc0d5f9b47945d484fd3d462794 -dist/2024-11-27/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=f70952c63e2eebd05acc326cfa667595535fc36db34bc0262fda4ba100ff2145 -dist/2024-11-27/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=0546a908cc12884801c35b461f98db01e87a7f92d276ca6cb6b89eb76c596e2c -dist/2024-11-27/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=3534e839b34603e4e2b32fb8ecc76163ea3b9cd9907c1a22fde4165860d1fb56 -dist/2024-11-27/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=b402a2e73debd81dc5cbc866f00c2ca82f676e2f923193674969af0ab34ad311 -dist/2024-11-27/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=fa69011557fdde5af1f78f33f9ba75a1d6f4488b9d8edd2958582593dba347fe -dist/2024-11-27/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=679be0bf62c7371b92f1824c8718662672ac3ef2d79e8af5c752fe34effbe333 -dist/2024-11-27/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=ecc2ba0da5c1057136eb105ec0727e55396e414d75efe0c2b96bef0477961574 -dist/2024-11-27/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=a89ad44842df861c69c6633ba79bf4ecefc38419d5669b6f22a265dd7be836f2 -dist/2024-11-27/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=051437ff7d177bdeb7a5a0eb947d27b8cf352c8e809b9311a1cc21b785a5a8b5 -dist/2024-11-27/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=1a4f50972104a95c404e778279a4acd42176cae45f58d316d601e7f38dc7bbc0 -dist/2024-11-27/cargo-beta-s390x-unknown-linux-gnu.tar.gz=bbe9812fe890b900e71aa4714dabd2f3e67bdc610fe0bbd5aea645ee807dd0ff -dist/2024-11-27/cargo-beta-s390x-unknown-linux-gnu.tar.xz=eebac7e8555f44ea9094750b61bd11d758197a72d4d436e1713e4bca42fa8080 -dist/2024-11-27/cargo-beta-x86_64-apple-darwin.tar.gz=6773b94f012a3d3589e2bca28f35dd23208fb245f107e4a17b8b3e7f893c038a -dist/2024-11-27/cargo-beta-x86_64-apple-darwin.tar.xz=d3a20dbd60545b0162dc06499317e342bea077cff369e053eb89e85e2b640188 -dist/2024-11-27/cargo-beta-x86_64-pc-windows-gnu.tar.gz=39e16c97c0b22533dfa674d6e8f5bf5df256e2b426d02dca5ed33e246f18d05b -dist/2024-11-27/cargo-beta-x86_64-pc-windows-gnu.tar.xz=ffd939f901c64a17c3f24fc69744cd2af1c176a45d8e5fa8209067ada403db7d -dist/2024-11-27/cargo-beta-x86_64-pc-windows-msvc.tar.gz=8addc12e74a983f3166b89d1d53ce87c92f38c7c3a62ec7c66580aa424d20516 -dist/2024-11-27/cargo-beta-x86_64-pc-windows-msvc.tar.xz=8e5622917395ff50e53b237e7322f1faf2b64f0446c41ccaa0096e57a3e7de69 -dist/2024-11-27/cargo-beta-x86_64-unknown-freebsd.tar.gz=2734d099aa1ada79346213aec8cc7ebe40312df1dfb40a32d09ccd3b6622e025 -dist/2024-11-27/cargo-beta-x86_64-unknown-freebsd.tar.xz=642edcaf16dd74c0935d28ce9b37cf1c5ecb9c03bec30f6ff0e7476760ae7ca2 -dist/2024-11-27/cargo-beta-x86_64-unknown-illumos.tar.gz=4f28de38005de48db7126dcb698b748063341de41dc71175605301837a3f7336 -dist/2024-11-27/cargo-beta-x86_64-unknown-illumos.tar.xz=ce18692f99780ec09d01816277ee4e71785bdfbd7abb4375ba8d87c1b6905ffa -dist/2024-11-27/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=f1d692c3a1c280f34de167ef26af3c13a6d0a3b5ae4fb86b0a9f2178c3287a94 -dist/2024-11-27/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=21f477af2b49ec8809bf8bc7b4c4919c7d2ac57782b829f5a0d9ef1967c5d71a -dist/2024-11-27/cargo-beta-x86_64-unknown-linux-musl.tar.gz=4bed61be221c1347b1649f54222b27e2a3577b84816ce1099c9f0f461c6e9e5a -dist/2024-11-27/cargo-beta-x86_64-unknown-linux-musl.tar.xz=33f463209d50ca6b04a8953c87d2177a84d1729d635de9a7c9b1a711ccb5d751 -dist/2024-11-27/cargo-beta-x86_64-unknown-netbsd.tar.gz=ce46b5b2d767cc0d790d8fd21052ecfb787dffb4218a238a339fe5f1afd26d6f -dist/2024-11-27/cargo-beta-x86_64-unknown-netbsd.tar.xz=0afd0489cb4231edc5bc1ef24a43c3f1918f681f08c1207d184fefdb46416509 -dist/2024-11-27/clippy-beta-aarch64-apple-darwin.tar.gz=6e5f1a85dad2b899567369aceac0102943ab807dad7e218c273b7b4d6393dba7 -dist/2024-11-27/clippy-beta-aarch64-apple-darwin.tar.xz=f784ac4a6ab180675396adf8256ac2bf2d1e823bef106d1c6c59911a8360692c -dist/2024-11-27/clippy-beta-aarch64-pc-windows-msvc.tar.gz=22f1e9299a24aebaf9a32471ddc6cdbf856b455d059ca077170aecf5989f8772 -dist/2024-11-27/clippy-beta-aarch64-pc-windows-msvc.tar.xz=7f3fd047ed5aa85ea6ca2b0d6103f7530d7d070c93b0f212c9d1a6491f160cbc -dist/2024-11-27/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=f383ecb5cd654268f00be1f577572993c38e7386a1e1d18b864338e87c7b2b42 -dist/2024-11-27/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=b2043facf587f98a8f10a92ae129b7f608297709f4ac61d683b7c813cc65e41e -dist/2024-11-27/clippy-beta-aarch64-unknown-linux-musl.tar.gz=6678d45195bd2a7b27ed2d4bad3790e6b63e376da71d112b9333760ea375c40f -dist/2024-11-27/clippy-beta-aarch64-unknown-linux-musl.tar.xz=f6c77e80c9ea4e312fc2715a9f66ea9a2e6344e3f04ab96cc572e4c0e8c915db -dist/2024-11-27/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=be8c0dfde3f09bf476d6600b530aa498b01415015665429bebed8814c7568b73 -dist/2024-11-27/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=4315f7623dcf0a278cccb6c8b397a29f83f70ecb9b03588f61e383e5ebaa697d -dist/2024-11-27/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=c31ff694c68f28e0f462133e783a5d732cf9c539737fc8dbbfd01a53e9a456c3 -dist/2024-11-27/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=2553ae5596b8273d8a61ec66d2e20d0c9733c9f791ca5c56217c60884f0ccf9a -dist/2024-11-27/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=1842cf2c26ab474df47e74720c56997e270b37609f840ac50ab0b05064cb38fb -dist/2024-11-27/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=e882b1cc2814e3c97c33991fa0a80de62556ce8f4f88307f6338a90be32b045b -dist/2024-11-27/clippy-beta-i686-pc-windows-gnu.tar.gz=7c6e08b841f21e3b8953e51a6a9fd9df0c719e8defd7b1ab0660d8920fe72185 -dist/2024-11-27/clippy-beta-i686-pc-windows-gnu.tar.xz=137aec194877446fec994a233427db419bb4f2910151c456c3ec80d9329628e7 -dist/2024-11-27/clippy-beta-i686-pc-windows-msvc.tar.gz=52ba38277ac3f80d124fdc8dd1709b8c1115cecfc53fae4731da8615a63f78cb -dist/2024-11-27/clippy-beta-i686-pc-windows-msvc.tar.xz=548d3eb599334ab98791b8ba27decff8b0de98dfcffadc994ad38aad6255cff5 -dist/2024-11-27/clippy-beta-i686-unknown-linux-gnu.tar.gz=448071394d5e647e8da8f64cfbf85e8305d85ff9357dd24737523c95eb339ab3 -dist/2024-11-27/clippy-beta-i686-unknown-linux-gnu.tar.xz=e25daa6264cf5e0a7cbcfd827e27a8e276c29c88c86cc15977c1a1650d0303f9 -dist/2024-11-27/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=9f080cc937e7209ad83fdb8bf4b2cd7b080af83dbd9061229f154785e273bfec -dist/2024-11-27/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=7d537f66195c581ff51ce8f53c4687a762daf225c7f0ce76393953ab04b804e1 -dist/2024-11-27/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=2bd38261a9ef33ad687b3edcd33f283c32a493a80b56dbefc822c1116edb1f2f -dist/2024-11-27/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=7e63dff1d8abe517aefeb4b1976932d23a9a7ed5e4db2398d8ba2659301f639c -dist/2024-11-27/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=1495b2a49cfce014da72beb691e6c477d189ef34080acb1761b588d11b75d27a -dist/2024-11-27/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=75da94f1ade2ef48674b77ded595c69ee715f62f9d9dd96e72039e27807b7314 -dist/2024-11-27/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=2d6b826fb4d3d9b61ecd3aaffdd1334f766dd5a5fb0d8279e0de26d381c5cbdc -dist/2024-11-27/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=f5ceaca2651d6002f232f71809458ad912bb5f00030790e907ff7b0e12c9e0c1 -dist/2024-11-27/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=1a62f307197c6fd08fbeabef89f58842cfd59c6d62f530850592fe55852d61f7 -dist/2024-11-27/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=4c65fd6a5d74527391fbc7c242a2313e5290209f5a15763d74eeaa6cba0a0ed0 -dist/2024-11-27/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=8ab9f735a98de1949e65d51c3050b29ceba3ddc28167ba0180353253dc726392 -dist/2024-11-27/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=0367eb23a9349ebd829d59fe0a2638557c8e57205e48f66a701b238461385bf2 -dist/2024-11-27/clippy-beta-s390x-unknown-linux-gnu.tar.gz=ffe9100ec6b81b081d5f9d840bdf01c658790d7e6bc0674e5ebb6b28f79c2f7f -dist/2024-11-27/clippy-beta-s390x-unknown-linux-gnu.tar.xz=b19b1b28bb7ddf8cf977f102acb623f65d5117c44ab8b62cf197f2d3d33c15de -dist/2024-11-27/clippy-beta-x86_64-apple-darwin.tar.gz=d986de5c01bde3469693dea7cb4248155ee9791550aa179d601066d27e45afb1 -dist/2024-11-27/clippy-beta-x86_64-apple-darwin.tar.xz=8000e46ccc2598fdb770c69c68aeb18d94db9b2847d0509f7a9c51ef28714ba7 -dist/2024-11-27/clippy-beta-x86_64-pc-windows-gnu.tar.gz=c701581f28d885889ae5c845a7b34beebb04a4631c2740e9333b69390cfaf499 -dist/2024-11-27/clippy-beta-x86_64-pc-windows-gnu.tar.xz=fc285792e6f626e133edede613a9a9a90ee12191765e2f0beac642a3b3c9ca12 -dist/2024-11-27/clippy-beta-x86_64-pc-windows-msvc.tar.gz=91afdb71bdd54e5c04fc7c933dac06d5e769627e886e20eb712524e852a01966 -dist/2024-11-27/clippy-beta-x86_64-pc-windows-msvc.tar.xz=2ef7018c7319e3a299c5eddf36748d9d293ae43eaf54662d9855fd211eb4658c -dist/2024-11-27/clippy-beta-x86_64-unknown-freebsd.tar.gz=02234d4c47478112e01d51bc7dd48cd467293e1eeba55bd383d08bc7376c471d -dist/2024-11-27/clippy-beta-x86_64-unknown-freebsd.tar.xz=a3e6a0c7f31278866d97816c5ed434b1987e0bc5a89b24283e836402803c1388 -dist/2024-11-27/clippy-beta-x86_64-unknown-illumos.tar.gz=b238ab536ac963929884da4dc9bab43679e6fa9aba4251c73ab7e5cbe5d8eeb9 -dist/2024-11-27/clippy-beta-x86_64-unknown-illumos.tar.xz=797ea7a7643a8302e45347f21c4dc6bdee617c2a9d9ccef74ed525c7d2e9dd91 -dist/2024-11-27/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=d630a6b25a08af85d3d426e73d3231e018e0ab7176a5934572786147fbbf3823 -dist/2024-11-27/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=d0259a0112f452ee49b8c9bebd760ab8945e5bc3a0d57b1cdc2b8e24accd35c7 -dist/2024-11-27/clippy-beta-x86_64-unknown-linux-musl.tar.gz=5febe478e5040f0f74a14c23e78eed21b080900d875d6b447354945c07677a6f -dist/2024-11-27/clippy-beta-x86_64-unknown-linux-musl.tar.xz=552c35bbe76a83439e66cf9ccd522d97e43a8fe4f6aadbabd1f02c4b2c1814dd -dist/2024-11-27/clippy-beta-x86_64-unknown-netbsd.tar.gz=ff6db2d7b84e1b01c81e494de15ccd07f60fef6dc60fa46d47e128ebaba4022c -dist/2024-11-27/clippy-beta-x86_64-unknown-netbsd.tar.xz=b27f89b175bee3769dab1c2d0c54f17ff3efba2038f3b600f4077435c7fd21d3 -dist/2024-11-27/rustfmt-nightly-aarch64-apple-darwin.tar.gz=5b5015483d0a98e9dc715c3cc8c23598c02fc14ea6e5878790ae68f2f1c8ef46 -dist/2024-11-27/rustfmt-nightly-aarch64-apple-darwin.tar.xz=ce5706f0397a1b2fd9e17dbf34ccfbc3e8c87cc81c92b54b81fd33accc2b7c06 -dist/2024-11-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=3f5077c8743b5c4f233da7d0aa0aa13fc488ef0fa9da24b002bfa413d52dc845 -dist/2024-11-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=087eb30f24ba7d8ee42e28bce2a6cd75e5fb7ef5dca8a738ef23fac82ad59566 -dist/2024-11-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=28a716ef9c5318543559ab4c0c2d062b0deeab1ecec80d5d83ad5effb574f209 -dist/2024-11-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=99cf9ec4b7bea4281f64a613784350a8ac34e9b0387fed7eb26d6f8c21c83735 -dist/2024-11-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=a23c3de89603bd4d1035a267e6ee456c6de12efa4029d76ded3edf7c69285a15 -dist/2024-11-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=462dfd28b631b5a6d8277920cfa8037d8583cbf6a2e5c9159c492161013e820a -dist/2024-11-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=44af5b13726cab40865580df8bc05182a2359eae64e41a92f84790ef55ca6bdb -dist/2024-11-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=0a7c0b207e745d01194d96f0fbe2402273d630d4f1aa05001a5f5371c9585a2c -dist/2024-11-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=66e2fc688b8f746d15c0dce042f2a94e06c5b652d5e0b6534d9e992eec186784 -dist/2024-11-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=15a2e087f7b482fa8c027fe6e6fbaf846d784c8e917fed375048a297d5e13c45 -dist/2024-11-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=71788ea2544f8349ec548a2f150dca2afe80a49deb91c00c46484a5e3039742d -dist/2024-11-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=d9fa7b780b9d8b93549abf0a3f0e6f31cc8e1e991ddf682adf3b616fe2a1f0c8 -dist/2024-11-27/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=30924bad51ffa62f762d4c000f86ea3457b590f6397d65755c711ff7f77ac129 -dist/2024-11-27/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=14fff13942e6a65927776c49013249b2e75aa3a630667ecf49c9ba721e47bcb4 -dist/2024-11-27/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=02d82688bdf3bd3c261a4a6d4acfb07835e29ce262cdc3165ba849a6a8490bcc -dist/2024-11-27/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=2a19b55bb609542ec49dea87e3b67532e5d18df8be43d0ad775bb34f4f9f96a0 -dist/2024-11-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=d07ca0ddfb0dd89a9cc935b2b9662379bcc9503cb28a28d68c5165f787a7d762 -dist/2024-11-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=de8106801b1e49dfd8a4fffbfc2a4f949218eaa011ca2085953ebf2a5ea9b141 -dist/2024-11-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=309024f86e80a4568721b5bb61aa936e027accc251fa97acd5043b513b325576 -dist/2024-11-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=55bf234aa2ec7fd4c6a7179f779d790e7f62969967519bacfeae84db5cd29abe -dist/2024-11-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=4bf9571182e7ef40e76c7e5905fab8ac35269ace390f5007480b4951f80cfa3b -dist/2024-11-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=2a2cde80fcbf68768ba7a99cb059a0cdc9313ad0c934383dde9598d6147ef756 -dist/2024-11-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=b747fb16b15cff3f9368ce1a1f5cad0d2930bde5a609547a3afa2679d7ab8a1a -dist/2024-11-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=b861f8361ee806d83f38afbbbf312e0e5e4d8851e7048444c409de1a83484446 -dist/2024-11-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=ebe56700ad0948e4dcd9930730f7df8e01a5eefca1d1157fe12160d782e2a5c0 -dist/2024-11-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=5081c9b8677314464d8a3a50220809def18badb2269d2cd8b7106f3547b0e25a -dist/2024-11-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=2ed9094b538b6450371311b742f2d309a1f40b2b4c84deb9867059336b76d1b0 -dist/2024-11-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=d9d52d9b9f4da7a457d05dd4645885d092f170bd2f751a49b4ab3b88395a5248 -dist/2024-11-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=a2e51d381645c6bf18502ca72fe9f10ffd309281dae87ec16c5627f232f77e50 -dist/2024-11-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=c526efc054c33a08626b882eebadf887a9aaf8fd60a4adf6a146659a7c1ec8d7 -dist/2024-11-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=04e5b7c97b57ff7d967abb4f98374f0833108c04f6edf482b8b3fefbde340956 -dist/2024-11-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=1829afdebce1c3fe249f81958de68c765db18b431927e54fc42be37ea4ab8226 -dist/2024-11-27/rustfmt-nightly-x86_64-apple-darwin.tar.gz=d6cf138d02e50168f8ee4a89abb2a4a39e19458d060d7b46cf227bba1fd4c0d8 -dist/2024-11-27/rustfmt-nightly-x86_64-apple-darwin.tar.xz=e8185262c82c064c4bb9ae6f1d3072819410de9cfca943b77605012a546c254e -dist/2024-11-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=64d78f9f05a978b95b9e22a63bbb31dcf98152df5638f498a361a96d9d2b0c04 -dist/2024-11-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=c07041ab84364ace58a357c18b5c4dca037852e1159edabb02f4579ac6853b4a -dist/2024-11-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=7ef0122ccd3a0c77c917bd75e93358eb95d7e87d78a165c724e3f0cd90f8209c -dist/2024-11-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=d0d0566a0a50e1e9e7f4251cf207bde82d96c27016f0a0acc364754561ab4881 -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=e4854528c31316894339bfa97b07ec607e8956877c285778e555885ce9c8a068 -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=d79c9b352ed7b2f132f06dcdf360527502b2153beb09cca968a5ced521edcd39 -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=df76cbeae0a61506a29db22e8743d16fcd97ef2da216ea15bf4d6cd709814017 -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=103cbb30bbe92da6666d84fab53dd7fe8105c2ebe62eeab5f6609488e62a481b -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=5f3c61663a319d6162240192f387e10ab87e2a972062198082158a243b667d7f -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=221b45c3928b1c45fedbeea987ad80750d3f55fbc564cf3ccf910a68447ad725 -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=18eb24fd665ce1cc4ce66b37b19c22397bff9369963b127137780870c179228d -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=bcd09587a21ea10953a14521e9e0ba7b5100e8e15b6a10cc4e7bd359200d5279 -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=db712c5e1d21231770e12dc95f6bcbe2f1d04b9cde61bc7adf8b529b41773adf -dist/2024-11-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=43303e426752dcd15964416822cdce0e5f3012366a9b77f3d68e6011c7bacd0f -dist/2024-11-27/rustc-nightly-aarch64-apple-darwin.tar.gz=95d543a835b11cb5ccbf0578df1ce4e1846e4915622d23a36cc6e18e44e17f29 -dist/2024-11-27/rustc-nightly-aarch64-apple-darwin.tar.xz=db9e0c51c35c81c2ec8be0838f3231f7374917215792ffee159e3d7ffed855d8 -dist/2024-11-27/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=bf9b83d6418bf97caf2df70a8e8298cd8fecb7b950cdaaa2cecbec243ed57c74 -dist/2024-11-27/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=bb520da5b522fffb5a20eed4390990c2ab9d22eb4f77196535a84ae7a434c9f5 -dist/2024-11-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=4072d9ca2d617d09d394139c0b8608bb8b2b8b2b4fa450f13c41975a16a791c7 -dist/2024-11-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=3d75a8a534e86bb55b63f5b5b2df66ae47862cb7f3ecd1591a829435031d7279 -dist/2024-11-27/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=3cf05e90bc1f95e92cca4769f74055245234037009cf464df3062238c88bc2b6 -dist/2024-11-27/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=245ebb7886cfba64d667630ca8bd672520cfece0ccec3b916e3de0f26aeada52 -dist/2024-11-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=dadff4abd2f169f9aa1910d4ea247b7d1f767fca74238ad31485b73399ab6dda -dist/2024-11-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=ff97e1201e9a305673e8a9b740b7696cc4cb5e86bfaa3e137cd8e3e28cffd7a6 -dist/2024-11-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=0c411e0824140323f51600d387d52bd01f601f5539d6457815e950224a6d29a4 -dist/2024-11-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=dc5731a70c393f69555433d522cde8a52893bfb88beec519c1bbb03b2a0e060c -dist/2024-11-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=01ef2f07f1222fbf3e0cfc5b957c287fb886fd0bd08cbf18f90dc37fb0b63541 -dist/2024-11-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=d45042b3ea0c0ce6befea7bfdd731e890dbd1f47d1992fe8718a1363f9f18779 -dist/2024-11-27/rustc-nightly-i686-pc-windows-gnu.tar.gz=5437da4c0b73d203789829512d856a66c1697d95afb1ffeaa6347ad0f7c04672 -dist/2024-11-27/rustc-nightly-i686-pc-windows-gnu.tar.xz=a7cb4cb627d75de1ade9211d8ea489ada9ac76ed38909751861ef0cb729dcbcd -dist/2024-11-27/rustc-nightly-i686-pc-windows-msvc.tar.gz=fd6ee6fc171459092e5e8a012d9cfb7491313e021d1c38965605836b5b101b0a -dist/2024-11-27/rustc-nightly-i686-pc-windows-msvc.tar.xz=314c7cd558a3654db85d75b3ed71da7cfec3614e4a5f2c449dbc6663b64c7e3d -dist/2024-11-27/rustc-nightly-i686-unknown-linux-gnu.tar.gz=7a1118011b11befb7df2df57e4450c7611bb3503b3b3cfece9c9c7d4a304391d -dist/2024-11-27/rustc-nightly-i686-unknown-linux-gnu.tar.xz=2cb95208e77546bcce56d8d5646c3fb5e49ed711894926cb50903ba10431a36e -dist/2024-11-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=4a76c4493e5ba19aaf14947a6c2e28ebfc7f2da530f1441a9fdfa328e15ea4cf -dist/2024-11-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=9b361904c691e17fbf44d80c7f7789511db1d8f251d65ba9cf6fda7f06fd495f -dist/2024-11-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=e89dc76ab061ae23081aee1619fcbf4a94e3acefef6b9b149231f3e1c22f9ec1 -dist/2024-11-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=11266d557e6d1d9155e6f04f65e4815cfbfd9f8e1aaa47221030e3ff11b22f78 -dist/2024-11-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=30f2eae1b8694607a04c836f750b4b7c204e1e14e52ec37885b9a821c2c9646e -dist/2024-11-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=495316e70b26140c66b074e9d7f714ab949f422c2635cab784a5e133538e4bb9 -dist/2024-11-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=ca560c4fe28051573d54f512652ac9740a2d1111aeb8e36b004a6ff9c325925c -dist/2024-11-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=1191f15bb6da98b01b43f0e9d7f51c5c45d38e3c5be2b4ae5f7c0c8fd25e9a90 -dist/2024-11-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=5f85829aaab919fa4b2fa5ac843b87358e8da4797adbb6eeaed5be02666ce964 -dist/2024-11-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=7c671d366fec561f0b568bfb4b6a08a6071303077a60f76da1307453e51ebc36 -dist/2024-11-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=300307ab6cf88afc4312edaa510769e901598492deec4834176c6fc9f3eef6cb -dist/2024-11-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=6fcf91c8679f4963f7d510cc8afbc24a1070b25ea6d20d5d31ad78ea659da194 -dist/2024-11-27/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=ab905f6f3119648c83a2f37ebe1a55b7899a5ac6d10070e4dbbfb89762a369af -dist/2024-11-27/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=13688b6857c8b10f7fb497f07c969d406cb6b76869957b5138f4b20fcc5d7c5a -dist/2024-11-27/rustc-nightly-x86_64-apple-darwin.tar.gz=e6bb782014e34fafdc5dcf3aeb407eb636d822d346c5a8c6227cc45bc645561a -dist/2024-11-27/rustc-nightly-x86_64-apple-darwin.tar.xz=6016ae620deddc42d1d6b6134b0164dab45a204089754b73db41ec837aa88a84 -dist/2024-11-27/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=ed3a381858612e25cacfd89c08496e9d06378d593ccedea4217ad4fa1ab326d4 -dist/2024-11-27/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=4819bb9c25aa743de7ab7e93b10b30336a87f1f75e5122d578df2c83fbc59850 -dist/2024-11-27/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=404aac87c77871c80f83cd7c59390af9af704ee468f40eba68d224d23e2c84e9 -dist/2024-11-27/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=0e1e0d2454ad24fe1da2cce2dce425bc1167bbca68832da2476c7996c00ba612 -dist/2024-11-27/rustc-nightly-x86_64-unknown-freebsd.tar.gz=946d5bcc3ac0b83fd0b53b60290a6361b179f16ba2aa6a2467789ad520278792 -dist/2024-11-27/rustc-nightly-x86_64-unknown-freebsd.tar.xz=f3bd1a053399ec89dccaa7456da41d54a8e91deb5c628e4c502fdcf34c5fe780 -dist/2024-11-27/rustc-nightly-x86_64-unknown-illumos.tar.gz=c353588a38705b7ae050d4b9868b6c4d3527295edbfb25c115b22cda4912be1f -dist/2024-11-27/rustc-nightly-x86_64-unknown-illumos.tar.xz=a71d8b2b42f6cd522da237f99492ed59cd34ea8c86fc1e73c8854c8234e1c980 -dist/2024-11-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=5116b949572fd6c7b11a079d9453b15a4c48562bce22b26d82b7050da772789b -dist/2024-11-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=3635df40363273d44c6f8182f5f6a3a099ed55897bb764cab2565363cd31c1f4 -dist/2024-11-27/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=5233af0b907fb7b176d2b5fee07c486e92dcbbbab1d54a60d814a827befaa984 -dist/2024-11-27/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=c908cad6d28657f1fdcbe9d84ecb86f247c75134803dd5273ca24c6c68a58f37 -dist/2024-11-27/rustc-nightly-x86_64-unknown-netbsd.tar.gz=c799165c319218a2fb4cdc0ac8db87fc9e2992a8e402d984ea27938a5ad1c5af -dist/2024-11-27/rustc-nightly-x86_64-unknown-netbsd.tar.xz=ec12763fa5d4cc150f663361cd245c30835e05e3b1928898b1b7300de559468c \ No newline at end of file +dist/2025-01-08/rustc-beta-aarch64-apple-darwin.tar.gz=8869795c998e9d39a7093bf53917291b066e35964059298cb1cc2ee2f1088b2e +dist/2025-01-08/rustc-beta-aarch64-apple-darwin.tar.xz=1397b1ee764dd51d8a082a063b6b13a2d5609b1e1a6e1dbbc0368f24e7830e85 +dist/2025-01-08/rustc-beta-aarch64-pc-windows-msvc.tar.gz=68719c1f92c6aa4251c27910c9f788472166444a9295cfa0af6450bc6b5e6555 +dist/2025-01-08/rustc-beta-aarch64-pc-windows-msvc.tar.xz=56fca9013ab1646263f043898346dfe206f4b264c37d1cf39fc61807e47c072d +dist/2025-01-08/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=7acc2b71f759f098c542f0ff4f3705e73112dfb3b8e85bb9158d1ce10d858efe +dist/2025-01-08/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=0d21e19b284d2053879ee55353f0d601e3b359530cfb9c747f6cc4ad9b67ade9 +dist/2025-01-08/rustc-beta-aarch64-unknown-linux-musl.tar.gz=25a5b2cf16fb51056c208e5899c9843bc3a902ae2f4148ac53f0b9043727e321 +dist/2025-01-08/rustc-beta-aarch64-unknown-linux-musl.tar.xz=31b1dead28d88897fcb2ccdaf72021faba9febe50d797e70ff5c29ae82179618 +dist/2025-01-08/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=fa8d3c93890425c9a0d130a652d3a4ecd018cb3098efe243a3ce8422539cb9ce +dist/2025-01-08/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=15344286d365042d9bd8cced1268eed508aaa6152d5e3e289fbd5ebc87788e75 +dist/2025-01-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=c5ed0dd8c2a3b609d9fdd88b027a1d628517107af8b5488a74bce9a3a4dbebcb +dist/2025-01-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=ff5eb5bc42dcfedaae86bf31af37c6c2bdb6210e98cbdd780c4e1a63ba37eaeb +dist/2025-01-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=6108711c53f07920a9afd0e749ff4228396220ec2eeacab2310e5b32af7a5e91 +dist/2025-01-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=7bd41663ab83aa4bef55f3c44e4e4cd3c4291c967573cf8b2ba3d60eda9d06f7 +dist/2025-01-08/rustc-beta-i686-pc-windows-gnu.tar.gz=12ba512d2dece4f9be9ac08f3270bfa6663aa28a3443f1cbd7f852ab052f12ab +dist/2025-01-08/rustc-beta-i686-pc-windows-gnu.tar.xz=834cd8f4962401dc522a5a0ac866561a62c646614a6ce4b99e91619098538861 +dist/2025-01-08/rustc-beta-i686-pc-windows-msvc.tar.gz=9915fde0d52fcc41eb5f5eb19c06be447187aaf3e5b4f438f7c20d92b364527e +dist/2025-01-08/rustc-beta-i686-pc-windows-msvc.tar.xz=e4e79679d6f90b5de5c64a534ff150416e48aed276d7426a1d4b1fc2e517cefe +dist/2025-01-08/rustc-beta-i686-unknown-linux-gnu.tar.gz=e394e8f0361f0f8a8a9653cab3ade57de10622651675e27c137cef2b06114a6d +dist/2025-01-08/rustc-beta-i686-unknown-linux-gnu.tar.xz=756965d724f5389a3cb63374b4287ea48e18d38827ac3af61a127fc6561ab865 +dist/2025-01-08/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=4e3483a31356c4c7c0a7041d318b36e02bcd25ac25c396e4dd139ff4ecad5af5 +dist/2025-01-08/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=9fcc0531f285832f5333762317ff64dd2506bc263e447f1931d361b15430d0f8 +dist/2025-01-08/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=780ab392bd8d879efc593ec9f87c1ff927e750fea4fdaae23d327fc363f8078f +dist/2025-01-08/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=bfad2585877df4fc99fe708187336631140a8170d21159a6deb7cd8f8ed20248 +dist/2025-01-08/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=30659e0526394f50ada52ce228cbe342e7ad9f6db2f0e1dfe6c8c63eb7ec3dd4 +dist/2025-01-08/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=e59cbdad42098b5f402f612c957113e7f7b8f4b4f37292079187f44d1753360e +dist/2025-01-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=adc19d38f3927cd2c09e2b4bc5e31b1b2473d45027b839abab1837ef22b6cb31 +dist/2025-01-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=35b15e40ea3b382d67e98dabbb93916abecb7d18977652760e081c1a112300d5 +dist/2025-01-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=31477a7164f8b3658bdf192bcb1383bb77f93e684887fc7b06e55bb469e7e25a +dist/2025-01-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=67f4e6f541e16eafa55e803e2c41fef1c892e7408f61228bdaabfb3a4cb41ade +dist/2025-01-08/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=2f4b8b12fc8bd7bd5783cc77e9b798de3ecd4a17f5a09d6fd4f3a528e1a243a5 +dist/2025-01-08/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=474f1a2b2f3a2379da02ba24c59a160a7ab0a2bdb4290b0b277d8aea8e441a53 +dist/2025-01-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=6be8f141e0a3f00abade77cde91405ac107d729f24b946c89831baa674c210d9 +dist/2025-01-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=897be1e29a2b67a9dc2d69195ec1f41439903dd3ad8a7b57eb339344ca6ec5da +dist/2025-01-08/rustc-beta-s390x-unknown-linux-gnu.tar.gz=b58ebbaeb5474f577329f4d48991222621d4f30f6411a00973951917586e2cf6 +dist/2025-01-08/rustc-beta-s390x-unknown-linux-gnu.tar.xz=215384ed943e173fcb4e10baa69d6929c99e8eeb4790365f1067bf20d5417b32 +dist/2025-01-08/rustc-beta-x86_64-apple-darwin.tar.gz=40a3d42489eb77cc7912af5580632f8f6f27373b0f691d24b7d249ca9bc84a41 +dist/2025-01-08/rustc-beta-x86_64-apple-darwin.tar.xz=6f8c83b96ba2d9bdb623af0f09b6227532d8c0c0f6ac19fb4b0c5f5145d2ee9c +dist/2025-01-08/rustc-beta-x86_64-pc-windows-gnu.tar.gz=1f76fb03cca2d0fe466c995467f209c28a68d8ad69e7b2fce521f4ace94106f8 +dist/2025-01-08/rustc-beta-x86_64-pc-windows-gnu.tar.xz=5bed9303cb18b7c5d78875b11463b945c9c9583c5b377efb69462bda0f92b190 +dist/2025-01-08/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a64fedbd98a9d2e8ca6d21018abf627367e2c81a028d38fb850253a6c94ef45b +dist/2025-01-08/rustc-beta-x86_64-pc-windows-msvc.tar.xz=471c040fe9f119e3ddf74fb8887d03cecc415109577a85c14917c00ab3348d0c +dist/2025-01-08/rustc-beta-x86_64-unknown-freebsd.tar.gz=468f89e4f6b7e72cfeeb19eeb723e723673487f3d1cf333d860623bf454e4ff9 +dist/2025-01-08/rustc-beta-x86_64-unknown-freebsd.tar.xz=c9e699c5fdbf0af0434354caf8745796db42a931669e733b3a7432baabf81974 +dist/2025-01-08/rustc-beta-x86_64-unknown-illumos.tar.gz=e0dbd7d05f74a1d444efb849700f98bbe6b00f870036e5cf6f065fc2d0b982b7 +dist/2025-01-08/rustc-beta-x86_64-unknown-illumos.tar.xz=1936046fd441ed9bf8331f77ac9ba930640523ded0674831912d28f9f7ae90c1 +dist/2025-01-08/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=c6dbeb9017e7f9694ddb05c4658250945e1d6c2b6de656306a3686d499653029 +dist/2025-01-08/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=adec507e847d746ef1bdb0464b23ef7fd840d17e7bff787a198fae239b69a77d +dist/2025-01-08/rustc-beta-x86_64-unknown-linux-musl.tar.gz=32714ed814213cc64fb1721c919c43a877286f625289bf5d526e247de0941e05 +dist/2025-01-08/rustc-beta-x86_64-unknown-linux-musl.tar.xz=fdebe84ac7370ca3cfa66cff6974c00e506aab6fb3ecb6b70e8e2c3ef92025f3 +dist/2025-01-08/rustc-beta-x86_64-unknown-netbsd.tar.gz=6443e8f6c2cd4d5f4a0b7f38e1c741061f42c454d006afc06ab87968425a8f44 +dist/2025-01-08/rustc-beta-x86_64-unknown-netbsd.tar.xz=c12851a0437c7ba6edf08d9ec89f2ccd22f05a5de661664142bf4f15d2a658a2 +dist/2025-01-08/rust-std-beta-aarch64-apple-darwin.tar.gz=e88734bd578a36ca396032144b25717e18ff51c519ff9490b193117516b299be +dist/2025-01-08/rust-std-beta-aarch64-apple-darwin.tar.xz=60f5672d8759ccf632e072cce922dd9d079a8e2325098b278afc4fa829943a2f +dist/2025-01-08/rust-std-beta-aarch64-apple-ios.tar.gz=bfd63a92d85035bdd4b4d445427c68483a34b41f647b09390de2ac9342ad6b54 +dist/2025-01-08/rust-std-beta-aarch64-apple-ios.tar.xz=9e9b941612bb29e317e4dd10ced4cdaec502526fa964b3aa29cd4fc2af070451 +dist/2025-01-08/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=2dc9ed6bbb9fd1d576bc78321a78f7997928a6a94625d90a613286e1a5bec758 +dist/2025-01-08/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=ecb686e8f201952f1e3475a88de73eb264a11c74961967bd1ba7eee87a248bfb +dist/2025-01-08/rust-std-beta-aarch64-apple-ios-sim.tar.gz=b481a6f88b8696b86160541083e608ef811f1ec0d9b1455325fd48efdaca6f01 +dist/2025-01-08/rust-std-beta-aarch64-apple-ios-sim.tar.xz=584d7a1cd7be4af3c747269de3466a312e541dfa17b1614ad355b32b74ea1ad8 +dist/2025-01-08/rust-std-beta-aarch64-linux-android.tar.gz=c91990c99c5687216320bb82e9e2f8f7b2242fafd534cbb0ae88a287880c2dab +dist/2025-01-08/rust-std-beta-aarch64-linux-android.tar.xz=c3a4a168393d0a8222b8ebdb6b5495a8896788156af4c454e35d349d1ab63109 +dist/2025-01-08/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=5a7c5b256b41a9ee01387da8ffaa49a3914737c827113beba081f34671568e84 +dist/2025-01-08/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=d0343608f884db1579847539eb6346ad3cb7b85072bf698598db61dee720793d +dist/2025-01-08/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=6cf78705518f865a7c6d3c9c4566b0dca6197338d5d88dc0037c721261e5dc3c +dist/2025-01-08/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=c8c81ffc20538dea3050a7b7ba89cab620423e66a10931befba354e2c4572ea1 +dist/2025-01-08/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=966f512ab3d23e303f7162d03bc619aff54b0af25bab86bedc0c96e130c89545 +dist/2025-01-08/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=fba9f964d8fb51753435c300319870a3b4530e385887a16d31975597cfde3ca7 +dist/2025-01-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=997d422eedd7b6adfd175ef6a13b5ae7a83530d633f834e7ca0d94851ed29ed6 +dist/2025-01-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=5ff49e69e9b549494542c9306c1fc82f6221b8d9e9fe25ec5021fe46f7c8cb28 +dist/2025-01-08/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=2181081deaa27438f420df53847b8108f96ad215369cae81947f0688b1906cc2 +dist/2025-01-08/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=f8b28aeeae9973c1dddbea684eec9a6a136fda3f850b4ffaa10e53914e1037e0 +dist/2025-01-08/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=a49eeccef00269063a10b1e623a54b0b500afbc2dd8e1db4ff8ae4a6844de943 +dist/2025-01-08/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=32fa668c9d3d703adbf6910ef358dbcab344d37fd3ce4e81ba43a820d8a8792e +dist/2025-01-08/rust-std-beta-aarch64-unknown-none.tar.gz=95c6a6a65ede296e8b4183a1271dd6cb1c61299f3966a8e2a6180867752a2988 +dist/2025-01-08/rust-std-beta-aarch64-unknown-none.tar.xz=a44fa8ccbc73899c013526ca32866f63e1165e7f3b14455b91b37e3865c9e1c0 +dist/2025-01-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=31448ceb30ff86b5d8b4e7fa8fe5871665115d561e6377f73e164d8f11652b6e +dist/2025-01-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=bd71a90489b9ed6134d0fd05fd22c58b20c271422628a552d04bbc2bfd1bd29e +dist/2025-01-08/rust-std-beta-aarch64-unknown-uefi.tar.gz=0cc22881954c661d2ae01058ca04db10912289812e9cfdbca3c066227e38566a +dist/2025-01-08/rust-std-beta-aarch64-unknown-uefi.tar.xz=439e6cda62ca17f124ed788ed8c3882c2999362067214ed911aa362b8d4d22b8 +dist/2025-01-08/rust-std-beta-arm-linux-androideabi.tar.gz=c62e75f3754b04b3594189de953ca6a8703679b29e8da3935ee5a7370ee0e03c +dist/2025-01-08/rust-std-beta-arm-linux-androideabi.tar.xz=dd23a5df6353aa01271f0d1206f927dc0f532203fbf66258b2771155e543b86f +dist/2025-01-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=2cf5fee1c6cc0e2ee099c8687126b11861e12b098dd4ac99397a2ad026596350 +dist/2025-01-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=d3a946d098ca9991b4dbdc4ba3b53e37535e62815f76f81bdf7e4562f3534943 +dist/2025-01-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=2eed53b995d0ac0c2856c39815ea08f40c074165c3814336af591adcd9f8b571 +dist/2025-01-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=3848bae0dfc660d40486ee56589fd0d6ee558f051a14b5efd9d55cd03d10f709 +dist/2025-01-08/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b40192daf614574f7ef2f7785f6b66d99c0876f3f3cdc30990f8545d41ba0fba +dist/2025-01-08/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=9e23ebe3062f38791cd23cfa58d9fbd796553bceff7a5a041d3cb78278915c99 +dist/2025-01-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=1b47d8f88a4496a8c7604aa2b6b0a2a810266825c385df5e29d313d5635eab6f +dist/2025-01-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=613dba102c8e8aed939ce3f1c43382d3d5d74a1baf911b7f68867ce0abaddbf6 +dist/2025-01-08/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=6afea3865efe25d2675c6e988c09c1fdfc052b27d996f893d9e5fe8a5aee10c3 +dist/2025-01-08/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=285ce1584fca2d0701baffb3228801c88212c20df1a6ee76bcc6e8a392de8739 +dist/2025-01-08/rust-std-beta-armebv7r-none-eabi.tar.gz=8bee2bdb49b1b8781b016b0b1032663e20d135d23b7d9de898e7dee0732a8ce2 +dist/2025-01-08/rust-std-beta-armebv7r-none-eabi.tar.xz=d0e2b1d1a095bb02866048e6286fcf762cffb69f437031ba3e7f330ec1ddaf07 +dist/2025-01-08/rust-std-beta-armebv7r-none-eabihf.tar.gz=c9a13d7fe85291c560786835a0531a407459f07cbfe4b652d9497a581e4bff09 +dist/2025-01-08/rust-std-beta-armebv7r-none-eabihf.tar.xz=be5e9534e88732ca700315d8a4517de3701201d74a0344e962faa9e9c64cf035 +dist/2025-01-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=9a48d8e2247f3f70c85e8a5fd39c9f1302d56aa94fbac6b431bff5a4c74f64ad +dist/2025-01-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=5e210bb961e6f73869671298ae1172a3a6f61b1b4ab08baad81e0e32e0a25245 +dist/2025-01-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=fc842d5db2778c0f3fff7602e8056795a0c33880a29ba0d29941fec2d2174d8f +dist/2025-01-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=cf473390797976ca153701dcd3ee41a4c2ba314cb180a06ee51e242f5f93047f +dist/2025-01-08/rust-std-beta-armv7-linux-androideabi.tar.gz=2cf80485cb303b44d48f6555ca33ea25fde6daa7f5fc9e6a2acdc23697c810a2 +dist/2025-01-08/rust-std-beta-armv7-linux-androideabi.tar.xz=625e57d27f5b4bc198598df7b2ae6ac8416951060eda7dd08ef9d319e97b2b9c +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=170d6999f1f9185d48df161023e527826ad72019c37ee11a4e3ad25fa1667e81 +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=724bf705fdfd23aa4065ec9128d6d34beaa8285b02f36c2a68d83b1f537c5186 +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=21a6727b7bee42a9ed22167600a5c9e8346db3e10133c88a07acca89a3513140 +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=f6234d0030296bb13cd8b075a6b2637b5f8c1c9454ff764a168755686fff4b5c +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=09479a598b1fe96eead29bc72f007a130b374b53d06be22282ad94ef7b4e4bce +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=7e67daa06adad6878ea5d3cd9626baf370188fde3e14b2459347665118173c5f +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=92d63ffb8ef0c274ff6138032e0df849b7d10668035ec3a20304ab31bafad495 +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=1c2e84999fb5282b6ed7bb31bac0f4c979483696453f3c797dce2e52b7bb848f +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=3a5e0748561fb981acdcfdc2037b12cdfb51d4fd3336172f6be74a78eeaca6b3 +dist/2025-01-08/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=9bd198313fe8e4d0d3b4f999841ad6310884f6a0ba9f1582e072108e38fbda0c +dist/2025-01-08/rust-std-beta-armv7a-none-eabi.tar.gz=45cdec4bacb8c1cb67e73c26499fa789fffebc981a33472f6b84d8752554e7c9 +dist/2025-01-08/rust-std-beta-armv7a-none-eabi.tar.xz=5222471cb625865c8a2594e88a3adbf529a866164e98f77a315953d5e3494c54 +dist/2025-01-08/rust-std-beta-armv7r-none-eabi.tar.gz=32159e59a8c11c032ab900f77ab7b25827409be390c62bfee8e28d9cd733c13d +dist/2025-01-08/rust-std-beta-armv7r-none-eabi.tar.xz=45c7ba589c6f092ada1a0acc0a107efb09b3baf0549846919ac3f853b574026e +dist/2025-01-08/rust-std-beta-armv7r-none-eabihf.tar.gz=4263a0a290f88e9b5c09c6140aaa02fcc7bc455439070f6d4b4d9a38f8424c3f +dist/2025-01-08/rust-std-beta-armv7r-none-eabihf.tar.xz=a3ff2f3691f7f62f9bb57259eb4e6c2976276fabc46e9ac6a7796ce2fd6ece5c +dist/2025-01-08/rust-std-beta-i586-pc-windows-msvc.tar.gz=d073f07548e5a2d92e094c69b6a7b59cf91309ebb42e06393c410c95fa90b681 +dist/2025-01-08/rust-std-beta-i586-pc-windows-msvc.tar.xz=e8708e2a341358c14c3259a8c4c05db6eb7baf09050cdab383b44f0b70dea7b7 +dist/2025-01-08/rust-std-beta-i586-unknown-linux-gnu.tar.gz=9072d9bf10db42db4e150b73fddf1085495979a18f59cabd43d73c0f1336e112 +dist/2025-01-08/rust-std-beta-i586-unknown-linux-gnu.tar.xz=e43a369c7954f4645243990291c88dae3b6694e4d2efe7ed4f81b7b8b7c723c8 +dist/2025-01-08/rust-std-beta-i586-unknown-linux-musl.tar.gz=e7de687f826c37e20b64b5e091fc3ea514770d38c45bb39eb6ab5a9730be6d11 +dist/2025-01-08/rust-std-beta-i586-unknown-linux-musl.tar.xz=5ab4c606c30f534fa75351160af4c4dda660955658a0d6864d28d927b9ca07cd +dist/2025-01-08/rust-std-beta-i686-linux-android.tar.gz=5936848fc7f45feeb797c6a78889762d0b36fe48dd82eb437049be6e8d17ee04 +dist/2025-01-08/rust-std-beta-i686-linux-android.tar.xz=d66a746f476ad27525c9f22136b664c0a98a811450caa083ff8c9def80dd886f +dist/2025-01-08/rust-std-beta-i686-pc-windows-gnu.tar.gz=d6326c139001357e964fcad7e26b195fb707e8158791fdfbcd16910258438910 +dist/2025-01-08/rust-std-beta-i686-pc-windows-gnu.tar.xz=f455268ea0f33118607adb1a7ebe484a38904e1c698899f4857492633fad219f +dist/2025-01-08/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=714846d27f13247f37edc266b66eb1792fa1c35d2dd13215800db55ed89cf8c3 +dist/2025-01-08/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=cede0b7977ee57ed24d792749dbfb42240f95a235d93b2e1a7ad4aa03d588da3 +dist/2025-01-08/rust-std-beta-i686-pc-windows-msvc.tar.gz=70fbea3fa87e1aa93668f2462ddf73b05c55883ae9d2bbdd0a3acc9ab51eb961 +dist/2025-01-08/rust-std-beta-i686-pc-windows-msvc.tar.xz=bc13da70c924372a2247d125bdfc850b9551e32ef990ca8dd0c24d282f9c7025 +dist/2025-01-08/rust-std-beta-i686-unknown-freebsd.tar.gz=c4583d916fdf07e7e274b59c32fe661b0c1780b925c4d84d01fccb1262cee70a +dist/2025-01-08/rust-std-beta-i686-unknown-freebsd.tar.xz=77612c690f5ecbadb1f2d9128f79676bc3b199478cdb619321eb521e4f8777ca +dist/2025-01-08/rust-std-beta-i686-unknown-linux-gnu.tar.gz=c487e6e164f31a9274a24a1668170db22e64def6412a38a38b6e0c4741523786 +dist/2025-01-08/rust-std-beta-i686-unknown-linux-gnu.tar.xz=cfd25efcec9004d223fb7257a34c0530ff755eb3337fe80468949df185e1adec +dist/2025-01-08/rust-std-beta-i686-unknown-linux-musl.tar.gz=5e208e822d9d2db30bfa4ca363d29d923c5560ac7d220dfd32898524022aa2c7 +dist/2025-01-08/rust-std-beta-i686-unknown-linux-musl.tar.xz=742f8c4dde07be899de43502af87ea1457a4706078ea7f353914fd31d9b91537 +dist/2025-01-08/rust-std-beta-i686-unknown-uefi.tar.gz=3567303608260def6590e9f0c29ce776ce933f0a9cf4c568faa8713935ee9efc +dist/2025-01-08/rust-std-beta-i686-unknown-uefi.tar.xz=dbea586494aeec9d2d29c80eb259cb6d66608c93b26f560f2276b490d6946a25 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=ecbacd29dc59c59ac513958325ce3a2a2323156562dbf966f529f267fc52ce17 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=69c2429bc0bdcb3e4ab9b05af37f65c60b936df6598d375843e63b8141371fe3 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=f4f33e673f883a9ac3b0113281c890839498d70d72e5ba51094c851bd6f0d323 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=c82917544801fe373b007aae871b4833db428a37d544e09644601d3fde682018 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-none.tar.gz=d3fb635af8745de8a5019bb9bbc3b20b109ed85f7ced6e939836bc0a124a0fbd +dist/2025-01-08/rust-std-beta-loongarch64-unknown-none.tar.xz=6e7e2d66e1c99507b1b515178d6a200532e1ae7600dc125d26b8ccf52d011399 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=0fb8285f64d616d741a32ae07f69dfa96e0d231cb835a839dc42ea76fdf0ea83 +dist/2025-01-08/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=c1c92ca9c3153ea5f42aeec0c3ee7f1042e3e01d6a91784e6baaf201c9621608 +dist/2025-01-08/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=1749eb869811470620cf5e432b5f5dc128c6b8e9f3b9586fc20336c677b863da +dist/2025-01-08/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=72c7a3c88afab27d0e4b09c313af336e6aff45046fae2becb17235affc1746f6 +dist/2025-01-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=36bd0cb97b921cdb915337ec1c7a23609c94c2485f932a1c27fd71804def533d +dist/2025-01-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=45a6098b27a0de50e3c26d540ab4afeac30178bdd389c0a4d829b015cc5726ec +dist/2025-01-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=00352c0a8fba406add478aa1bbf6b6ca99e7c5db302901616bd2cc740a9867b8 +dist/2025-01-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=69d7ca4226590875ae59a45b45e7726780dcf4091c9c44c3759931e2b05a42af +dist/2025-01-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=6243b4efcf2435cf586248ebc9b99379e8b86ce5575d8845821a11c21f8946fd +dist/2025-01-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=78898b9d99a25075a8c47e7b78e35b64b891179a8f54d41983370814f33b6eca +dist/2025-01-08/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=ab293f2e7e3288a4c4842ee510307f18c9df6618702695add978bd1d56be21b1 +dist/2025-01-08/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=57b7c326e4167d01385f9f89d89e81b5b660a7e63e1c17b14b70e8c8e50774dd +dist/2025-01-08/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=167fca173e6e2974a35be4c8fc5cc9043a3b34d74efba13a86df75d2600576d5 +dist/2025-01-08/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=4197393d32094f65fc781bf39ba95fb36988508f9ab6b41300ebe2ebad838640 +dist/2025-01-08/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=d3d0569bffb348bc580f3e382557939a4a87452a05dcfe1fbca8c8a9888c457d +dist/2025-01-08/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=c0ad9def2f73a60b674b35b8f53483a0c017ad4e4db3b268b3c10bdbedc13625 +dist/2025-01-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=7f41fade9abdf4ee47e96ffcf345fc37231d60a645ce814b19738689018b77cd +dist/2025-01-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=d6f21bf60530c691a6d40d0ba1ebe0ee041bf8a333f489671b1f1fea61950ffc +dist/2025-01-08/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=0ddc2427ea4e448789b8053f111f7310f6da95d6cff8f644ce1f3ccffeb16f42 +dist/2025-01-08/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=77a2f8531ec6a87ef95ed5690c31d5e1e3cf65a633e0ff885cb0b2cc55a2fab4 +dist/2025-01-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=c72a5c97347dbf43c328170cd1ded9363f1f3659732d9497d73bc2a9e3b32de7 +dist/2025-01-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=584e99c8fdfd6e186509ad41f67d02ad92cd9d887c2b6159ad8a36334eba7aae +dist/2025-01-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=536f1135a697180ed7674b8d9ac15232eac4d7735cbcc836cc099cd6136c39b2 +dist/2025-01-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=dad89574543674fd72dd2a6be4b2753b4e2211238d6208b201903c0645024fa5 +dist/2025-01-08/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=1fb747dc33e3016ec5f0d8161dadef20f0798f7a65967c316f0315826bf7e8d0 +dist/2025-01-08/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=05c57bfecf04cfb5279a3132138c9bf0c6773ea5fa01315bdcc83f0ad06165c5 +dist/2025-01-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=83e04e9c3ca61c2aa39a0c37b92d11a8571792244e6c5ebc795c1c3274a9a926 +dist/2025-01-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=4c1537651b695764db9ae3c536a605a7a9a1fdf51689350f7fff9638454844d3 +dist/2025-01-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=1c3164278134db89dc7cc5d2169402f28757e55c99438cb86a90cbf06f07ef7b +dist/2025-01-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=ddb7ffbad2e308d80b901986f6e00f38ecc59359a9f7d28223c089b01ae86f91 +dist/2025-01-08/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=935d864e0e212ed9f70027fa7f6afe18757e561347c4d8b97221db2936a5afe7 +dist/2025-01-08/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=18cc0e5b000474a60938521e23c5ef057e184616ddb1e2b031db0f8b5d87931b +dist/2025-01-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=e824c24bb3933941658a3a6c981e469c153aefc5bdb153216d90cbe8dc26adf8 +dist/2025-01-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=d40178695aff134127268c21a91ae8b4aaedf2d78122a00c844e0c4efe246815 +dist/2025-01-08/rust-std-beta-sparcv9-sun-solaris.tar.gz=c37a91e3c6685a11bc96acb1f7db48c30a45ed19c9a7f303ad4b60bb24228975 +dist/2025-01-08/rust-std-beta-sparcv9-sun-solaris.tar.xz=cf190f95859df6eb65ca3cc07aee95d4f3f8c0770c480ecd8373168cf0bce323 +dist/2025-01-08/rust-std-beta-thumbv6m-none-eabi.tar.gz=b598d8aba2ac570320ae7a1c8b9103f04cd0b81df37500ed838b88874eb7317c +dist/2025-01-08/rust-std-beta-thumbv6m-none-eabi.tar.xz=ebd4c1ca68d4ca5944a3f0837a8a1018e18dcb31ef8436a4d02c347b251ff0be +dist/2025-01-08/rust-std-beta-thumbv7em-none-eabi.tar.gz=3d0385fdb184a66a1af91e3db28ea0829b1a498f2431a896aeccf2c900cb9624 +dist/2025-01-08/rust-std-beta-thumbv7em-none-eabi.tar.xz=f778bfbb7033a53c61c3af187ee35e9e7713e9e98a6994f11ed9b589f3459391 +dist/2025-01-08/rust-std-beta-thumbv7em-none-eabihf.tar.gz=0a1669fc57856b2e475a9b8edd7575ad7ab07ad0b95a0ba9fb92e7fb26f81a0b +dist/2025-01-08/rust-std-beta-thumbv7em-none-eabihf.tar.xz=bb6b245b183061f65e3a5d9e9c1bafc76c3f968ed7d0cbd0e33ff878f5e30804 +dist/2025-01-08/rust-std-beta-thumbv7m-none-eabi.tar.gz=3f459b3a6dbe99fa6bcce86e853096902f23e7e49a1b8c300ef4515796619b28 +dist/2025-01-08/rust-std-beta-thumbv7m-none-eabi.tar.xz=b9ce85bf7cfcb13526c2cbf56aba726919b818168c6f99fb855cf00ef8d0c76c +dist/2025-01-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=366797feb0b31dccd500310903b494682b654800938a79c46e47313accaf622a +dist/2025-01-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=33c50d91b1f23770031a3e1c9b3a78f901b30831bbed8c7f463c29ebb86d5a91 +dist/2025-01-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=43acc164b41da62e1aeb7f252f6d81f1f3b79281362348817134760185648071 +dist/2025-01-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=c93bc0681027e879719417049e61ddf7f4092d72d103d14994520bccaf6ede19 +dist/2025-01-08/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=0b36bef54f41302c871bfb92f45f248c34bd2450b159c68801eb13373d464e69 +dist/2025-01-08/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=7f9300e17e4786747ca434c1f1a0451aa7c7f933f7952b5010a0e4bf4d9e4198 +dist/2025-01-08/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=ca421607c9f67d0648dc7550781bf90983dca6f17e81153ebcc4ae2f69fe88a5 +dist/2025-01-08/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=0b20c32941914bacc1b0a16b334cd32feed1ff56e6a2551aa0ae6b22c41f4c46 +dist/2025-01-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=e792938012865b5c1fcec63bc25a9b72e28889515472cfd83d7d57fd8f84d7c5 +dist/2025-01-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=15338fd8f01e0fb422336ba055a4ccf4be3ff8ccdb123ace84e9dc9f1a64e3cc +dist/2025-01-08/rust-std-beta-wasm32-unknown-emscripten.tar.gz=c57a71f14db1b122dec0ff70a04faf1b8a7a3af948e3ed81b15563b19c376334 +dist/2025-01-08/rust-std-beta-wasm32-unknown-emscripten.tar.xz=dbbd2251d206de84de81abd5b29e4ed1b08c00155141e08a7b6fa35559ac4e65 +dist/2025-01-08/rust-std-beta-wasm32-unknown-unknown.tar.gz=852381932ef65b7ce75f943164ac747bcce3b1d3f6e2c1cd434934c1030f789a +dist/2025-01-08/rust-std-beta-wasm32-unknown-unknown.tar.xz=cbdf58a9afb016aee98416924578d0a8ece8a6d5a17734606928bedf37719129 +dist/2025-01-08/rust-std-beta-wasm32-wasip1.tar.gz=6dd459e217ea3b4f7f85811eca500c774a36dd849addd9874e4e54e972fc7c7c +dist/2025-01-08/rust-std-beta-wasm32-wasip1.tar.xz=beca27838a50a2da0341d1bee58faaab18d67a41cd1724d39b30b4f8daf18359 +dist/2025-01-08/rust-std-beta-wasm32-wasip1-threads.tar.gz=8a264acc2656f35e61d4ebf8773dd3b29c0e7748ccaf326898089838128c609d +dist/2025-01-08/rust-std-beta-wasm32-wasip1-threads.tar.xz=eac3340c629af165b67982326cbff6cd63a2721e41972b70826a9911af902e02 +dist/2025-01-08/rust-std-beta-wasm32-wasip2.tar.gz=ddef01fac3d8b1116b0f2b5f7b4a65a54070e06ccff8fc0429ed8e668d57d4fe +dist/2025-01-08/rust-std-beta-wasm32-wasip2.tar.xz=6de7754db16d34a556264c6d37ed66480e832aacf2aefe34a7e82636ccd38653 +dist/2025-01-08/rust-std-beta-wasm32v1-none.tar.gz=8f8eef02573a4911630ceb59534bb91a084ecc9d8ba1ccfa6e59370f69af028f +dist/2025-01-08/rust-std-beta-wasm32v1-none.tar.xz=86bb30d39659171af2120a86668f1803f3c1ca7b2a0f8662fc98a499734f9e17 +dist/2025-01-08/rust-std-beta-x86_64-apple-darwin.tar.gz=b4e018a5dec5b232867770a8d8ce43d670265a51b389c7a1f0f1652a9e2b685e +dist/2025-01-08/rust-std-beta-x86_64-apple-darwin.tar.xz=b81c60d6b6c5f5fb1eba3037c545452bf7f070eae7b6c23ab3011f50de1f01ce +dist/2025-01-08/rust-std-beta-x86_64-apple-ios.tar.gz=61a88f5fd29b413ae351db90a43773ad2cc846ef3a03b5747e98bcab7865b988 +dist/2025-01-08/rust-std-beta-x86_64-apple-ios.tar.xz=977ad619301f051e241f898c302bc230ed37dcd6041d925378cba6811a15f41a +dist/2025-01-08/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=184c6fb1f051685f23a04ee2a57d15b8f1f3d5696b9cee0f8d48b230f108f408 +dist/2025-01-08/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=90715fa792f08da57964abae2b8366337c3372ecb92624783448ee6fc921792e +dist/2025-01-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=13343f16a12d12bf5dea13e240a88e50855a3eaa16d87842e33356611ef6a0dc +dist/2025-01-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=f273923ea18276e3440003bfe6f00479df907dffd18fb80b447c41baae396cb7 +dist/2025-01-08/rust-std-beta-x86_64-linux-android.tar.gz=3c86701e32a065bd9b0529360379b86180724497b5167f776253abba208db741 +dist/2025-01-08/rust-std-beta-x86_64-linux-android.tar.xz=daf93cde1b13402a2e7ef7faa2aa1644cacb2fafb211a28d4e1c7cb96e738372 +dist/2025-01-08/rust-std-beta-x86_64-pc-solaris.tar.gz=5cf8d53338a4c504dfb96dcbef5b2862921624c2c93edc7597478f97ef3f1a24 +dist/2025-01-08/rust-std-beta-x86_64-pc-solaris.tar.xz=a8a4105596906d4b1ac1588c1b301c1843c4ea695219fa6a979205a6b5fb336f +dist/2025-01-08/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=f9c03150ce779c7a31ccf5fa4e12953af8d182bd7c0415300ea0ddee191a0e47 +dist/2025-01-08/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=fb81f14fc43c8c9e86da1f10dbff6474447029781b716c9ad67068f793f07ba5 +dist/2025-01-08/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=de329a0e32d0f66d50da01875c85ac807b826d2d2efbf971a7b46f89710dd2f7 +dist/2025-01-08/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=ea5ad2523161e086b0b898c8c989fc1b20a26b460f4403eeaa9fde881be58465 +dist/2025-01-08/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=b042f515a81b7151a0930e852fcb23632b74579ddd8be53dc37bf09fa94747f4 +dist/2025-01-08/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=6f850810bcb1ab381e0245ce7d7881d86852d041d679d622dab4f4317aca54db +dist/2025-01-08/rust-std-beta-x86_64-unknown-freebsd.tar.gz=e415f16fbe3bfd0d9283ee41dc385f3a1a79f33730aba9d04da2acf7ea993617 +dist/2025-01-08/rust-std-beta-x86_64-unknown-freebsd.tar.xz=ce6967397e9dcf20c700957d5ef3a8fbe35795f0b7be1e8f2fc61ebebdd9771d +dist/2025-01-08/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=6233e4e853dcbfe5dab0b1258fdadeec39f3d343fd99e597956677a949de1945 +dist/2025-01-08/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=228a0ccf377f633b450b6bdaec99f351cc9db41e61d3caeba85f675bc9e07954 +dist/2025-01-08/rust-std-beta-x86_64-unknown-illumos.tar.gz=d729b6e0f6d70104c730e7cb4d4472ce02452acceecabf98e411b2ad0d6cfdfc +dist/2025-01-08/rust-std-beta-x86_64-unknown-illumos.tar.xz=51dad4bf611ab3bef919a9961f1a4d02f0203c63db501e32ff0810b2a1d81617 +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=6c859df64c707c7783863a17e2980c2139a98293473363efa6873d6549b52e3f +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=f4cce8d15f242168ba0ec7942a1140b1dadcaeebc8c0e7e7bd35ef7f91e4b390 +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=f7a559f89b5fa340c2974b8c85aad21e48995af01add8e459b82bae890f0b2e5 +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=73007a7a396864a71003de912ceb847e8684c4c63d45f032da628267aa28cb7f +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=7746927bd5283c05717e006d252bba797b48bb9f50b3674587025125e1916ff7 +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=4d2cc7aaa081dcc0b9fbf09601881023b6749d8b2986a01f82caae0218d2cdc9 +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=6f2ecafe9003c8fba1f43e1acdd477cf0482e7f97c1687d6255c696bc45cf662 +dist/2025-01-08/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=c82ece042d0980b1707d3871aa35b4b816179c3214e84ca7666e2189e4f062cc +dist/2025-01-08/rust-std-beta-x86_64-unknown-netbsd.tar.gz=d41dcec02cd3dc2536786aa461256bf5ce1b65174ab6cc532564dbfb6dbb37bb +dist/2025-01-08/rust-std-beta-x86_64-unknown-netbsd.tar.xz=cfc7dd1eaf1420db8b87d13bd9a857e258c2db4137ce1fab03583b82cff5e3b0 +dist/2025-01-08/rust-std-beta-x86_64-unknown-none.tar.gz=234209f51b8e8637cb2742cd482be0a333e4463869abbd5f00e548f03eb79483 +dist/2025-01-08/rust-std-beta-x86_64-unknown-none.tar.xz=36a5a189997d1c6eb05397007223611fc9777cee6fc495a885e46c2f52f62040 +dist/2025-01-08/rust-std-beta-x86_64-unknown-redox.tar.gz=a8df20db51fd121a970d6dcd24e583ac831c956f37b7e47b1533cba6f4b27dd4 +dist/2025-01-08/rust-std-beta-x86_64-unknown-redox.tar.xz=d1368bfa84bae9366cde19cb201fd13fe09d2c0b53f82cabefa85a78acf423e2 +dist/2025-01-08/rust-std-beta-x86_64-unknown-uefi.tar.gz=625834a177f20b99f706b9b25c60388db6cc42de7dd54a9ae10b16a86f4ab9bd +dist/2025-01-08/rust-std-beta-x86_64-unknown-uefi.tar.xz=89a95f2c6a11a0788fcb4fb12c7b37dcae62ff682ae8e1d24910f64dcf801be6 +dist/2025-01-08/cargo-beta-aarch64-apple-darwin.tar.gz=be3bbcf4c95c1d30634cdd87efaf0ea57b8199649a9e502245ee3915f93f49c5 +dist/2025-01-08/cargo-beta-aarch64-apple-darwin.tar.xz=74eb6c112313e7bc0104e211397ef998c2713f3c350a0b8995355ea04f4c1df6 +dist/2025-01-08/cargo-beta-aarch64-pc-windows-msvc.tar.gz=089863e43456e8c2613cf63f82172c9b2b220d582d448a88a9301f12aa5471e2 +dist/2025-01-08/cargo-beta-aarch64-pc-windows-msvc.tar.xz=fe604aaf5d859192fa13c78643c072d49b31f1b16fdbb088e2917631aa683431 +dist/2025-01-08/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=f4c710be8d286696c57bce005e43458a5031fec2b706a8e825c498e7b1c9faa1 +dist/2025-01-08/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=18e510f07b0a6b94cc1ec14503c7a2c992ce17c9897c472d9330cf55514ca4c2 +dist/2025-01-08/cargo-beta-aarch64-unknown-linux-musl.tar.gz=b2a4e280c9150683d14ab98770a4bb6f27c74144abcb0d075e81e537cbd2e2d0 +dist/2025-01-08/cargo-beta-aarch64-unknown-linux-musl.tar.xz=096d0926b219a8dbb6952a66ff742936c7307baa236262b2d6ee5238c2b44153 +dist/2025-01-08/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=58eb3f62b876ee4be22ca51720204da9c3734a5a4a5365dedcede0a012a48891 +dist/2025-01-08/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=1ca32ac5479c6d27191c7726b0dad38af34e6423ba8e644461ca30c82382ce06 +dist/2025-01-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=45895027f54b7c4f1222196317ac1cc38a84ccf07696a72fb91b2d42218d4281 +dist/2025-01-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=f08639a9a86802637b08df47815e2b0e32ce826f76c7187a140f97abf1eaebf5 +dist/2025-01-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=63dfd33bb41426e81a8be487580656699502396350cd6c50a3bf32cacf2f5eb6 +dist/2025-01-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=1033972fe7345a4cb84d0ba8a479159bdda53d42f581a7087eb517144026e870 +dist/2025-01-08/cargo-beta-i686-pc-windows-gnu.tar.gz=2f00a1e75d995f89ad2b5fd509dcbce97aad2096638cea05d0e9662fe8f21997 +dist/2025-01-08/cargo-beta-i686-pc-windows-gnu.tar.xz=535e4ea02ffcb59ab5c492689aa25aaa7dd026a9db7e5a5e1a674464488e86fb +dist/2025-01-08/cargo-beta-i686-pc-windows-msvc.tar.gz=e2c01590495c6c2384afb0287104bb9e9d8ba555c100c18c8bfd7f06bb4daf43 +dist/2025-01-08/cargo-beta-i686-pc-windows-msvc.tar.xz=6ace1bb6fb5cc03358433476d31f25076eb8d963d685df9c8dfc389a9caad479 +dist/2025-01-08/cargo-beta-i686-unknown-linux-gnu.tar.gz=a50b87367e59dcc3a1c22101d69cbf45a1485e42b2e12b6211d0f35059698d36 +dist/2025-01-08/cargo-beta-i686-unknown-linux-gnu.tar.xz=76d25cafff7f67abe142ba7183b9e1a1fcc18bbfe6969ea03783fd1cbdc7cd68 +dist/2025-01-08/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=3bd98bbaf3c1f718e4f40aea4dc0ad47e6c33b46b4b169841497b49a582b7caa +dist/2025-01-08/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=62e384bb07173661c6c1e6ddad3d0fab31a25184966020f70b8492c916cf852b +dist/2025-01-08/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=6bd1ed4631ae5020d4529fc404ef4cf6bf4a93616fd15e1cad9527277fbe200f +dist/2025-01-08/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=e27425b6e8f6c5114aedce100068bda25be975d80761d6478c49588c45f3611a +dist/2025-01-08/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=2b14ae8e9f383d2682292ce26bb5dbe9dab69b450564a5e3f7db3fb93864a21c +dist/2025-01-08/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=dcb68fdece4a4a365a95c440de9bd360f8c1079f4f15eee3d61a53d83957c7e3 +dist/2025-01-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=9e9c94abd8fcdea831451105bc351bd9407f3ab4925226a171cb0d170a4a697b +dist/2025-01-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=4cdd8795488a4c6ffcf9bc446576191dcc364e58dee785bf3ac2e756e3a9d5fa +dist/2025-01-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=4eb0a9d2a1b85326c393250873a4550c8e6617e56df9a2d313aa220ffcb7a9ca +dist/2025-01-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=2cf68732cc6926ae9727f627e64fab12c9fbe8803a640b25697ff6af23dbd8ab +dist/2025-01-08/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=4f276075cf0ce993ac88728992369d996dcbe4e1f68e5e80e620c0a6b305a484 +dist/2025-01-08/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=5b52acb5500d93fdccc9bdc03e6e91313deff0a2801c2b8a587681239b2a6ecf +dist/2025-01-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=8325fda118d5da0b376c0db751cf2ceeae2dd3021b930e3b55c14e02d0ac438b +dist/2025-01-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=2a764695907dcef6b4259831636d0020e72dde5d213f532b3f04b0bae3615d4f +dist/2025-01-08/cargo-beta-s390x-unknown-linux-gnu.tar.gz=12045986bfc2c346a914bd0b18d84d3e1c3103d6082b08659aa2508a483e0817 +dist/2025-01-08/cargo-beta-s390x-unknown-linux-gnu.tar.xz=ed09f5e3c37582c4ab42f0b4ef1353ff29182579818be28d8a184b33bec728f2 +dist/2025-01-08/cargo-beta-x86_64-apple-darwin.tar.gz=d026df870421796b76749529fd0a7965d83c2d915fa42599613c7521f92e391f +dist/2025-01-08/cargo-beta-x86_64-apple-darwin.tar.xz=b2174c6efe4336f76d30f55cf83dd5604b2a4f706a76be1cc57780a45d5fe1dd +dist/2025-01-08/cargo-beta-x86_64-pc-windows-gnu.tar.gz=7047bc8731c2eb00043f0237a12f5261942a1b6b99d574cbb6db32f2f1930180 +dist/2025-01-08/cargo-beta-x86_64-pc-windows-gnu.tar.xz=578f2d6d433dc249fe923edd0519f3db953c0a9beb8a2f2641e1bdb65863526b +dist/2025-01-08/cargo-beta-x86_64-pc-windows-msvc.tar.gz=0b4dadaece478e1c0cadbb479bd2acffda3254f2ca3c2529e3b81a0357019239 +dist/2025-01-08/cargo-beta-x86_64-pc-windows-msvc.tar.xz=19dc7572f4ae2a9b46c9017f78c5ff7108e9e293f21a3a52eba03f29dd204f62 +dist/2025-01-08/cargo-beta-x86_64-unknown-freebsd.tar.gz=71672eeeedc18240a33ea8b0ee0ce2ca8fdb020d5701cf4b8d3cc464a0199cdd +dist/2025-01-08/cargo-beta-x86_64-unknown-freebsd.tar.xz=e853f0e42602ff80f64fe245863ba0a4f50d8197ab4cde56c4bed53f4d7d9cbb +dist/2025-01-08/cargo-beta-x86_64-unknown-illumos.tar.gz=42c1b82bfbccc05f381376b59c92d453810ea57d85e206b9ad958d0e9faa480d +dist/2025-01-08/cargo-beta-x86_64-unknown-illumos.tar.xz=b83b7cfb56b087a0dc648eab5f695104a1f220896a2981d2b65f67aa1584838b +dist/2025-01-08/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=0b87cfd9dd3349b23fdcedad9a0fca316ac59e720c4c8f7b67c44020dcaa9665 +dist/2025-01-08/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=19883a7bde6ed9a4587469f0c7bacb434b9734eb74c4b9c570fd3c217db6a52b +dist/2025-01-08/cargo-beta-x86_64-unknown-linux-musl.tar.gz=11934bf3879a9c395676b9fb737fc9e6e0b54314e51008875a72a80d8e773a74 +dist/2025-01-08/cargo-beta-x86_64-unknown-linux-musl.tar.xz=2ccf643a305060f2fcd24b957a8f9db28dc6fbe44d1b947007a571cea976d973 +dist/2025-01-08/cargo-beta-x86_64-unknown-netbsd.tar.gz=f9982255fb124e74a79708e9e566fd3713b904919260ea498279cde580c9b899 +dist/2025-01-08/cargo-beta-x86_64-unknown-netbsd.tar.xz=18bd7da3c593a0bdcb14140ce19e5a43d42e041fb897fa4acf12f35e03b2d766 +dist/2025-01-08/clippy-beta-aarch64-apple-darwin.tar.gz=511e0a0b6bf59a8e9ff299a32e46586ced5f13a1ad43c9564921c27b905457c3 +dist/2025-01-08/clippy-beta-aarch64-apple-darwin.tar.xz=dd75a377e5a28aff5eca49c73b0b52a2141f347fbb3d2c164d87122663c60ed7 +dist/2025-01-08/clippy-beta-aarch64-pc-windows-msvc.tar.gz=3097ed66faa8489f2fac32453d2ebeb7bc39d5d58b2fa60d47e5f539a57d3658 +dist/2025-01-08/clippy-beta-aarch64-pc-windows-msvc.tar.xz=dd26d47db7f35a41eb16829b35079d2137eb41a254c810e8a9e6d393a899ed96 +dist/2025-01-08/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=a3bdd2413e3d040a1063113d6ba868ed4ffad157f97f180ce6410dc07d89fec4 +dist/2025-01-08/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=308402abb63ae6e364d4ef014aa9dcf338b86982a25fc0570c4ca0e348b50bbe +dist/2025-01-08/clippy-beta-aarch64-unknown-linux-musl.tar.gz=07a3f0f0f6eca797d9feb6b3339a7c87ac4063bd4c898cb49d3a61c43b7b8ee6 +dist/2025-01-08/clippy-beta-aarch64-unknown-linux-musl.tar.xz=9b2fbae0ec014d61a3d20e532b526fb92bde03ab154b0ee02cb5aa4071c319cb +dist/2025-01-08/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=9d6c781e2414d9ba43648fa958b2cee3937fa62d118ffbd7ae11fd71ca797011 +dist/2025-01-08/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=73d6d532acdcd6c64f48d12a24ee4abb6f46c6dbfc3d5c3d593887e98313c1a5 +dist/2025-01-08/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=0d698e42477ce7c068df67b389e8f63f82649e1e2b38324e3c3b8906ee9f056d +dist/2025-01-08/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=9b94df3a1bcf891595a8263a61e3aa82a66013a5c59e8d8ac7742e033a1ac590 +dist/2025-01-08/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=c010c51bd0665e4fc8a3d0bc27af75d2bd112dc8cbb841252b3d44b3789665f8 +dist/2025-01-08/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=c7f9ecb195ded5ac7a03d353e51c264e5ccb4a3460733b06fdf967d8e3a5f085 +dist/2025-01-08/clippy-beta-i686-pc-windows-gnu.tar.gz=5f4ccf0aaeff0eb0970796ea23aae4590285b42b62b165fe3898649e203f57da +dist/2025-01-08/clippy-beta-i686-pc-windows-gnu.tar.xz=4400d650806cbdb2a8e8e2d6ed0bd5f90fa46b8f2398f09fed98ef565135635f +dist/2025-01-08/clippy-beta-i686-pc-windows-msvc.tar.gz=062eb313a72787fe53435c57b8a5b0c16ad2abd0644d8669038090d3572bc94d +dist/2025-01-08/clippy-beta-i686-pc-windows-msvc.tar.xz=ae493ceb9e334b05345cd94a26b87f317909ee82c02f704c2c3b487f5b28e897 +dist/2025-01-08/clippy-beta-i686-unknown-linux-gnu.tar.gz=0d7ba60792aa6e5cd531362ab92977ae3368b2ca2284174019133c2ed9d495a7 +dist/2025-01-08/clippy-beta-i686-unknown-linux-gnu.tar.xz=ded4113933755736c3248f1b0e26cc42d436eb4c6cbb21745f87a2428eae6ae9 +dist/2025-01-08/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=a4525272c4d46ab120d61855d5e453b92b0fa83623c8c5cdf4384b746ba56925 +dist/2025-01-08/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=5acf5b947a7d7f546cc405975ce5eb1f7e1a86ffaa6ea7c18f5baccbe8e26a7c +dist/2025-01-08/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=628a86af3590cf6ec46173bfd18790958618e1236d3bb54f6eb92be7f78cbdc5 +dist/2025-01-08/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=970c1e229fe35bbeb251e6e1291618d9da5334c1608685d8d602209bccafb4e8 +dist/2025-01-08/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=25ecca37c54464052f44b79ae061c992f9bb29a671881f5fdc7a8f4e1953e543 +dist/2025-01-08/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=e353972b9c73228c523077137a000d1c265dd24012fd1f3f44cb16ab172561c2 +dist/2025-01-08/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=b6d050a3cde8ff3c94dd072fce770ddf43486c8db37ca2ce2096f427f169cb81 +dist/2025-01-08/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=1728393681aa26afdd9b4c6147b1cd95a43e614cb379fd2f0e38fd68b26cd1fe +dist/2025-01-08/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=4136945a33e3658464835c0c31a244b953b1bc2614dd38266f650ee8e330d5fc +dist/2025-01-08/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=e121b45e188df1d540bd3d3d691b0b4043d5d067b52286e3e82c544d1f059a38 +dist/2025-01-08/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=6323723980ac6c17e951272bf5473b0f3735d05f00a469317d0371db9f1b562f +dist/2025-01-08/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=9f7120352e4b0e147159df5e04c1d1939dfe0e1081a6a0d8915ab75709147079 +dist/2025-01-08/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=32f52736c78922bb47a624365f3bd7a06d28581ef4f1fffcb57575b6de739431 +dist/2025-01-08/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=50c2b4e8c57bd0f4aed56d88e1bfbab2fc8f6c6e6d2aa8cf83dbb36067f2ca69 +dist/2025-01-08/clippy-beta-s390x-unknown-linux-gnu.tar.gz=5c2082cb9fa73e0af8b3384a3caf76c7dccbe7a78f553a5527b3539bbee83c0b +dist/2025-01-08/clippy-beta-s390x-unknown-linux-gnu.tar.xz=ca8c580219fe697b9dae674edb2a2c6ea6c737ebfc4d2580cb184745625874c0 +dist/2025-01-08/clippy-beta-x86_64-apple-darwin.tar.gz=83ac808792dadc4e5779c0b2185514de339cb61359b185d714713ab366909de4 +dist/2025-01-08/clippy-beta-x86_64-apple-darwin.tar.xz=c6a92d2b255736788cd53cb99b84e20ff135c4e5a7ed9cb2ccc9e5eb37523239 +dist/2025-01-08/clippy-beta-x86_64-pc-windows-gnu.tar.gz=6984f5b15e2f56e12924cb251d99f7b52307b1368c47ddc6ec4d17bbce8959e1 +dist/2025-01-08/clippy-beta-x86_64-pc-windows-gnu.tar.xz=fecd2eb58e8e1c9422e4433f120c3456f9cbd0f216863d9e3d37129bda966f79 +dist/2025-01-08/clippy-beta-x86_64-pc-windows-msvc.tar.gz=674115dee679648c45203b9014ce2aaf3812b3de079fc12aab4ba34aa4d8e8e1 +dist/2025-01-08/clippy-beta-x86_64-pc-windows-msvc.tar.xz=892ca2c9bb499ab0922919d89bba3c176e75570be2f4f2a1ac08608ba490d4cb +dist/2025-01-08/clippy-beta-x86_64-unknown-freebsd.tar.gz=513b3402e525d1e28c648a640d4506f9456c5c2fb45e2b7bc7f2c325a2d2f920 +dist/2025-01-08/clippy-beta-x86_64-unknown-freebsd.tar.xz=5e5a6c353aa3c8cfaafa694e70b69ed54a8c8dea5ea46412fd191a28be3bd926 +dist/2025-01-08/clippy-beta-x86_64-unknown-illumos.tar.gz=f16841404d8bb2aa1bd530eb6c2850e665c9e90f82eb6968cfcd4063b5ff8d10 +dist/2025-01-08/clippy-beta-x86_64-unknown-illumos.tar.xz=3c23e2df43a58499b4cf3652b2b02b1f68141b417829eb06d44c977c745fc7ff +dist/2025-01-08/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=43bda68cf861a73c8e9bb461e4c28d3c5315f04900db68168584db4f85e50492 +dist/2025-01-08/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=0d3bac2b017cb529d3fcf81042edae79362842f191a6759441afab41b19cd0eb +dist/2025-01-08/clippy-beta-x86_64-unknown-linux-musl.tar.gz=af7613a78ea98f2f134a69a32bdc09a103f83d6b1ea2ea3c27ddb3eb74430695 +dist/2025-01-08/clippy-beta-x86_64-unknown-linux-musl.tar.xz=78baca17912ad3cf49214187471ddcca890e787dc9821daf37103ea9f8632c1a +dist/2025-01-08/clippy-beta-x86_64-unknown-netbsd.tar.gz=f85ce010c7d235358e532b23e85ca8fd287376c311ca9427bd41ca0b3f04510b +dist/2025-01-08/clippy-beta-x86_64-unknown-netbsd.tar.xz=aacc604a5b53267a8eb936a433eba97ad4a002558836c933548152fc6cf50b0f +dist/2025-01-08/rustfmt-nightly-aarch64-apple-darwin.tar.gz=1ad6d3a92bfd2398af3f712b8238014b5517c80c54e2334e6bdf5bfec349bf0e +dist/2025-01-08/rustfmt-nightly-aarch64-apple-darwin.tar.xz=fcee1911fad43cb5689786b9603ca43fe2e6fccc89aec1f63b8afba4df915a71 +dist/2025-01-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=3d219a1e888acdccaf75afc7c7820f45eb2161a0c78304f76a28af95c5a53dde +dist/2025-01-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=0b4ea270256e8efb6df7d60473db256455fe7d5de835f164bdd0a92c3cea7369 +dist/2025-01-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=a7edc1692f4a5975fa5877e1af63c8e9c0a2d0946086413678973990fda8ee50 +dist/2025-01-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=bd4b98f560d00da97f2e7899ca32729581f9c5a386f398cf477c1ba6c922029e +dist/2025-01-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=49387f42c45fcb21d55e056843ec3ea210c89b10722adfd2ad6ee5d4a929f7c8 +dist/2025-01-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=778b995192beced6c690d80103c719e4b30c16b5e3caa2e2586693baac7ead18 +dist/2025-01-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=906191d5b2ca8e7645d6ff8571419aa8b50ca62fe10a1934722f1a493230da83 +dist/2025-01-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=6944b61661c3b1f72ec86a80b222bdc0a20e88a4e2a2f342bbb7ae2f8a1e1a6b +dist/2025-01-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=e7fd3ba048b6d20956f6a76b6e859204bb9847bbc1305482426bb40f5b28ad36 +dist/2025-01-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=312042e89eb0007fccdc5effa6098a762b94ff3a15840dee0fe681486b0ebda6 +dist/2025-01-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=584de19a62f85c418d01bc7943f0e3793f4c79776b8aeb5a7993cd1e7141bd7f +dist/2025-01-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=43327de3051396e27793390468003d1f13da0f0ed1cb7d5224ededf2787fefe8 +dist/2025-01-08/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=bbb72a900c77cebec9cae4b2c6fd0e3bce3451bb2fb65fabfb9f042a55163f78 +dist/2025-01-08/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=fbf8acb567141328ca628bd3c81af9477eb177bb398be3feef55d57acde2af5b +dist/2025-01-08/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=4a80751fdd514a71d20d440260a86510c83cadbeac3bf03014ef5377c6530e10 +dist/2025-01-08/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=fa3d56f5ec9f88448a2b6c36809b6c21bacb2cec7350571d386320aae2b410e5 +dist/2025-01-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=0f11501ddf7be92b987404df21fb4ed83ec8893d887943d86031709e7d671900 +dist/2025-01-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=264accec3e4ff18a3f21508bdc22988c86c0c899be83ed491f7f45f4d8d1f76e +dist/2025-01-08/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=a32c70abfec103c12119a5adceb83eae81b7fc950733e6039e0b3d3a589d16c5 +dist/2025-01-08/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=b0ed3c98ee0cabe8e85d031539796f0ff3e6fb3ed90275242d6fe9f55900abed +dist/2025-01-08/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=b4f8456e420eea3025f32303cda5de26c67d061e04fb2229a247411ac7dd8351 +dist/2025-01-08/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=e66969acdf2d98ffd854f19e7d9f8beee8ec8fe7ed4493bd308b2f9b44cd9c90 +dist/2025-01-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=f97621947a0a90815867d7a0a08722f87cab26584a4b61dca7d81e50336b16cd +dist/2025-01-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=9af1743797ac19982892046c5d4d1865c0fa1e7cc0a38ef43f2364e215a2b5ad +dist/2025-01-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=fdf25dcd2c911c4fc6fbb3a184d078e36cd908a6a7b135c2a48a6f6efabcfd78 +dist/2025-01-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=6df2621585eb4d0c5be9b3118034b70dc12e3ac999a47e843b9b2c8ca48629c8 +dist/2025-01-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=bd6c79723c219e2c2b56bea90e3c2808bdf2119d299fb84d11d021895292d464 +dist/2025-01-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=4e1f249176e480b12ea11bb49377cda875189f382086339ed3ce591e3c7576e1 +dist/2025-01-08/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=36877f682d6c43aaa755b5edb5599e9ee8f48969e93532f458f516ac052dd47b +dist/2025-01-08/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=ef36ffefbe132c56c3a993ba4f8b9048f65ac87f3f22e9471064d3fa7c0e9bbd +dist/2025-01-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=2d9a0f3c007b59fb107c859ee4eab0ceadfe4c220ba45bc8c8f4bf5cb2608ba7 +dist/2025-01-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=f09cde2c36a4b9791f1492b0319ef1444418b2162215d48d18a6eb7493dd275a +dist/2025-01-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=585ef59a9fcb414ddec4fb69a6c33548a38b62c87be3c707443954c7be9eb764 +dist/2025-01-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=4da9c4095b0e30d61c9617a5cbfd69ebc77d54f248dfa3c2f9c096383184a762 +dist/2025-01-08/rustfmt-nightly-x86_64-apple-darwin.tar.gz=28ed0f8745b5b68527ca735a794b11a1411574cb0756b74b7e5ad1f0652f1670 +dist/2025-01-08/rustfmt-nightly-x86_64-apple-darwin.tar.xz=6b3c264c1e1002c381bc952ae5f24f56f7bd623067ef0f0179677798539d0aa9 +dist/2025-01-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=46b9ee6fe5c5bc6ec504b62fd9356cf467ea001cea073056fd8b53265b424940 +dist/2025-01-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=d888eaa7a4b42b4761cba736c75c29d047e31d6d3918c3d64e8347236918f035 +dist/2025-01-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=3b04474137945edf639d267a67712166c07df4c018276dfabbd7ad714c952750 +dist/2025-01-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=f5268dc4d20eb86ae882c5faffdc1b6dfee52ab4487569a02f92e2e001a936ba +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=6fe48737c200f3ab1ebea3b5089403ad76a8dad4754cbdfa274c89dbf9b0ea45 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=04f1a8d21dc54470df735f6b1f09e9d6e26c106d4ae4405962aaed11da80bea6 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=0dfa280e767a16665aad2bb6051b88a84850ccc408a24d99b89bf8d659149833 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=601215d564ed36cdd9be9abfc3ba42bbc15fc75d306e0921b36083a293067980 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=ce5f4421a454ac2e5f8e53d0ab6050be45f73a3931b9e60240b13f7bf06800ee +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=7cda6e670d0718d13b89225f58df1c6a2473e6d2626144354c854d671c778ba2 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=26e3275bab7d39c465bab76074dd54f534980c89f5460838da9745c171859604 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=b33178fff841b91968c2f6fc108389a1740d865214729406de40b49e6969d22f +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=cc8439ce6628f864503c7ca322ec0607000536c002895dc872ad1bca8e865119 +dist/2025-01-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=2d3c2f666bf57384e11f12dcb00346f73953ca8a2a60947ae5c0b14b856b9170 +dist/2025-01-08/rustc-nightly-aarch64-apple-darwin.tar.gz=febc42bc953bf6b23253670756fb294545a1db22b02fbe2273e1030a78f0dc8a +dist/2025-01-08/rustc-nightly-aarch64-apple-darwin.tar.xz=f978d9d9e0bcc75efd4250406b796fb3f6cae31ec41ca2a40f88f7e70201171c +dist/2025-01-08/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=6dfd42938c385aba18ba477e4430dd89e9b780d9217f410f68094d7bbbc722a3 +dist/2025-01-08/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d79b6f6158a99ea82314a99a68c52c63deb16d777d74426780df06c5110576a5 +dist/2025-01-08/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=5dfaa19982b344ba8d3f59418a847a764eb8b6b4a9809b8a63aeafd4725cb406 +dist/2025-01-08/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=dbe770d4594c9f8cd27aec8d342fd5f6bb44570723228726cbf19424dc0d7708 +dist/2025-01-08/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=41357e54d974f3dfe0e71cac0eedc69625ddf7e2a1cf563c2e9689afa53cef11 +dist/2025-01-08/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=208ffbee7b68121ddc0cb92dc1ab73dc3b489869ab190abd99174026724a3493 +dist/2025-01-08/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=7970e126f177ea336cc243448d034c8ad1aa6489db36ea0bde54e2df472552df +dist/2025-01-08/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=8333efc4f3bf9d6fb01a947a6f631f03fd506a494060e426ee7621831dfc3a95 +dist/2025-01-08/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=f8b9030db15e6004647772700a7b137fe9e7ff1c24fa0742c45a25d072e1f1e4 +dist/2025-01-08/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=f554b976502cdc78735def853947d9b48ab1ff1aca208cb348efdedae0df407d +dist/2025-01-08/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=402109bd4811e723999c8747978452e2a96e2ddf1109393302f9c1be7e36348e +dist/2025-01-08/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=b2dd7f94bbc34b91fd2dc2c1bab7179a51265bc51ac58b66c8aedbe849103749 +dist/2025-01-08/rustc-nightly-i686-pc-windows-gnu.tar.gz=9e3f1aa453de7bfd9a15f1925d96b46ce6375b49c6656db14bd2ed99f4138e1c +dist/2025-01-08/rustc-nightly-i686-pc-windows-gnu.tar.xz=468a157752c69bb2096ffe91413086d04eef8c64b9cdc44b51d7e9a94d2f4b5e +dist/2025-01-08/rustc-nightly-i686-pc-windows-msvc.tar.gz=1a9977db5843941c49c808830364e32c7e57190d3bf4dcf74e2a109473f808c0 +dist/2025-01-08/rustc-nightly-i686-pc-windows-msvc.tar.xz=7cc68c40929538b7711f5bccfa964841094eed9859f490846de0db0b2ba74343 +dist/2025-01-08/rustc-nightly-i686-unknown-linux-gnu.tar.gz=08c86c8984b966d3943de2252318aad2a27899fb58c5eb1079b8b8164b56d21f +dist/2025-01-08/rustc-nightly-i686-unknown-linux-gnu.tar.xz=d3b53723f085887709951dae7b0389b8cd4159a22fc7189bf7d7bc15ecb4bc57 +dist/2025-01-08/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=515db325eb12b211d08367436fd07f5ceff4743930b9e685b0b13b94b99bfa34 +dist/2025-01-08/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=b4986e7aca0325059689f8d7ead67616b2965922e77da33d9d03a7235520b585 +dist/2025-01-08/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=541571e5deb51d360eeaf2c88a28cc25c98dead983a3b8f2a6e3f371df3ce0cb +dist/2025-01-08/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=44fa8d77bf945b1a5ea9ed2a7e8228c8c0d5770098bbd8687173dff58b7005a1 +dist/2025-01-08/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=1ecae3935e253cc9b7aa44c8e7835fdf039d44ae19080e2316421b47453e3527 +dist/2025-01-08/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=b512b895e9b78069e57fce8c1982ea6fb8e463fbfe626474a6399008d5c149cf +dist/2025-01-08/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=91c4ddebe0b50e8778297793d77a583b23b6c333d785564b97ea38a137c3b7df +dist/2025-01-08/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=562f81acf112aefc6878132d7cf352da64b0eb1803d8c371e6713e270bea15bc +dist/2025-01-08/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=147bcd50f63f068a5814200ffeb8adc775c65187fb9c178dae5468af3fc04611 +dist/2025-01-08/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=9b6e863729599a96547119c1c2a04f23167cb142447644b88ccaa86d073e1471 +dist/2025-01-08/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=85c085bf2771eb79dd3aca31ff9896de969de229c0549bd8c89a539393ef5cab +dist/2025-01-08/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=107bba3499f4446aec6d79919453341a0d10fa5e6001da4cc9d3f1a618871989 +dist/2025-01-08/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=ca6663608404909610479a33562049d313882ab8252fd302657598b0251746ad +dist/2025-01-08/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=f66d3d9a1d897346945b254aed29e29b82be1255908dd0accc7deebd698a0b78 +dist/2025-01-08/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=480fdbaad5a5e9d6412682c61de324ac37093f60377e5f772c59dab58e63e6a2 +dist/2025-01-08/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=c438d14d90ed5acfa2108788b7179aebd7fcbac10703b2c5207ed7eaf988ddeb +dist/2025-01-08/rustc-nightly-x86_64-apple-darwin.tar.gz=b91f15c087c859b8ea6a5d556835c296ff480f6927efa9e535b9dcd726c8c4de +dist/2025-01-08/rustc-nightly-x86_64-apple-darwin.tar.xz=64b1129ba56b964ad433a499b2b5dd590371a4a7fa0f859c551bced786d876f4 +dist/2025-01-08/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=c90d259076abbb62f26348a2bfaf5bc1dca1e6ba7d4c1dec8f02d9dfaa21cc53 +dist/2025-01-08/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=127c2335d668cb93169681ec3775e0c9a91e0c5e1dd6043bd9236e18b7dedbf1 +dist/2025-01-08/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=a0dd89c80a4c2c724a8910c33c6d5159beef9b462f912326c659defb87ebe41e +dist/2025-01-08/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=b2c1972028521d6cd643a7a1f4db2eca1da5eb8ea03187bab5a7bef63377eec4 +dist/2025-01-08/rustc-nightly-x86_64-unknown-freebsd.tar.gz=3eb87ac0585b6a4a3cd0525e3f7fc04eafcb28b64ddb866beedbf24401810bf6 +dist/2025-01-08/rustc-nightly-x86_64-unknown-freebsd.tar.xz=fa93c78e53bc3e408c1b6d7917e643fb7f1f6203ec4a44036e8b73d37e650b82 +dist/2025-01-08/rustc-nightly-x86_64-unknown-illumos.tar.gz=3017ba6134aaf6cae0b7980ef211420ae1c09d230fc082e9f68a5a1a7335aad2 +dist/2025-01-08/rustc-nightly-x86_64-unknown-illumos.tar.xz=5a5881f7883eeb638c00ccc7a4cf453ddb987983228b066ec955b92d4e4855a7 +dist/2025-01-08/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=9c7796ef52678a29ea7e0406c1f2273ee11d907b379b3616237df9a05505140e +dist/2025-01-08/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=0c978e79f9794221ebd7c0fc0d4313e323d1aef1a5358ffc9cb806fcd997e4ef +dist/2025-01-08/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=21ff96c7b7c0a5a18051c12f01b67e90fef620c887f7d91e78944b5a1a0e8838 +dist/2025-01-08/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=2b7ffa8d546ed9b89472fd25ac56b4f6e968e99bfae9045a4019fab319716cf4 +dist/2025-01-08/rustc-nightly-x86_64-unknown-netbsd.tar.gz=ea30e5cef50b7b207844bc30ceaee4bcd30cde86f636080b243eb3e7e5367042 +dist/2025-01-08/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c07dc61336037f475cb74945c0925fabd1fb33412eb4e6eba4004f207db67f3e \ No newline at end of file From 2af3ba9a8aac4948596a98d4308b08317c005faa Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 21:26:39 +0100 Subject: [PATCH 121/189] update cfg(bootstrap) --- compiler/rustc_ast/src/util/comments/tests.rs | 2 +- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- compiler/rustc_hir/src/tests.rs | 2 +- compiler/rustc_lint/src/tests.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_parse/src/parser/tests.rs | 2 +- .../src/parser/tokenstream/tests.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 2 +- .../rustc_span/src/edit_distance/tests.rs | 2 +- library/alloc/src/boxed.rs | 9 ++-- library/alloc/src/lib.rs | 1 - library/core/src/arch.rs | 1 - library/core/src/future/async_drop.rs | 5 +- library/core/src/intrinsics/mod.rs | 32 +------------ library/core/src/intrinsics/simd.rs | 1 - library/core/src/lib.rs | 1 - library/core/src/marker.rs | 36 ++++++-------- library/core/src/mem/transmutability.rs | 5 +- library/core/src/ops/arith.rs | 14 +----- library/core/src/ops/async_function.rs | 24 ++++------ library/core/src/ops/deref.rs | 47 +------------------ library/core/src/ops/drop.rs | 2 +- library/core/src/ptr/metadata.rs | 5 +- library/core/src/ptr/non_null.rs | 1 - library/core/tests/ptr.rs | 2 +- library/std/src/prelude/common.rs | 3 +- src/bootstrap/src/core/builder/cargo.rs | 7 +-- src/bootstrap/src/lib.rs | 2 - 29 files changed, 49 insertions(+), 169 deletions(-) diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs index f88b534a0c114..7a87ccea62a7e 100644 --- a/compiler/rustc_ast/src/util/comments/tests.rs +++ b/compiler/rustc_ast/src/util/comments/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] +#![allow(rustc::symbol_intern_string_literal)] use rustc_span::create_default_session_globals_then; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index c8500098add1a..94746212138dc 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -692,7 +692,7 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { .find(|feat| feat.gate_name == sym::generic_const_exprs) .map(|feat| feat.attr_sp) { - #[cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] + #[allow(rustc::symbol_intern_string_literal)] sess.dcx().emit_err(errors::IncompatibleFeatures { spans: vec![gce_span], f1: Symbol::intern("-Znext-solver=globally"), diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index 953e48a6d3347..e0e63d183c63d 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] +#![allow(rustc::symbol_intern_string_literal)] use rustc_data_structures::stable_hasher::Hash64; use rustc_span::def_id::{DefPathHash, StableCrateId}; diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs index 186dec5904b49..f49301b0215db 100644 --- a/compiler/rustc_lint/src/tests.rs +++ b/compiler/rustc_lint/src/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] +#![allow(rustc::symbol_intern_string_literal)] use rustc_span::{Symbol, create_default_session_globals_then}; diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index c8715f94d5dd3..1ea075c2cb368 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -867,7 +867,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // First up we check for global allocators. Look at the crate graph here // and see what's a global allocator, including if we ourselves are a // global allocator. - #[cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] + #[allow(rustc::symbol_intern_string_literal)] let this_crate = Symbol::intern("this crate"); let mut global_allocator = self.cstore.has_global_allocator.then_some(this_crate); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index c2b5e318bda72..e02c4871f35bd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -871,7 +871,7 @@ impl MetadataBlob { let def_kind = root.tables.def_kind.get(blob, item).unwrap(); let def_key = root.tables.def_keys.get(blob, item).unwrap().decode(blob); - #[cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] + #[allow(rustc::symbol_intern_string_literal)] let def_name = if item == CRATE_DEF_INDEX { kw::Crate } else { diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 3f8d66c2c9580..c222aaa9a8676 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] +#![allow(rustc::symbol_intern_string_literal)] use std::assert_matches::assert_matches; use std::io::prelude::*; diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index 037b5b1a9de5d..aac75323ff3d2 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] +#![allow(rustc::symbol_intern_string_literal)] use rustc_ast::token::{self, IdentIsRaw}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6ee02e9f47f15..c47c3f64bf6e8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3155,7 +3155,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - #[cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] + #[allow(rustc::symbol_intern_string_literal)] let existing_name = match &in_scope_lifetimes[..] { [] => Symbol::intern("'a"), [(existing, _)] => existing.name, diff --git a/compiler/rustc_span/src/edit_distance/tests.rs b/compiler/rustc_span/src/edit_distance/tests.rs index 9540f934d7ebe..8372856c0d304 100644 --- a/compiler/rustc_span/src/edit_distance/tests.rs +++ b/compiler/rustc_span/src/edit_distance/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))] +#![allow(rustc::symbol_intern_string_literal)] use super::*; diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index dcc1d0234d365..1b5e44a913467 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2028,8 +2028,7 @@ impl + ?Sized, A: Allocator> Fn for Box { } } -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] impl + ?Sized, A: Allocator> AsyncFnOnce for Box { type Output = F::Output; type CallOnceFuture = F::CallOnceFuture; @@ -2039,8 +2038,7 @@ impl + ?Sized, A: Allocator> AsyncFnOnce } } -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] impl + ?Sized, A: Allocator> AsyncFnMut for Box { type CallRefFuture<'a> = F::CallRefFuture<'a> @@ -2052,8 +2050,7 @@ impl + ?Sized, A: Allocator> AsyncFnMut f } } -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] impl + ?Sized, A: Allocator> AsyncFn for Box { extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index aff90f5abb3a0..784af9407692a 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -91,7 +91,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(async_closure))] #![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index 95d88c7f67991..cb130f60cecf1 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -65,7 +65,6 @@ pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))? // When stabilizing this, update the comment on `core::intrinsics::breakpoint`. #[unstable(feature = "breakpoint", issue = "133724")] #[inline(always)] -#[cfg(not(bootstrap))] pub fn breakpoint() { core::intrinsics::breakpoint(); } diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs index ea6d3b800e64d..f1778a4d782af 100644 --- a/library/core/src/future/async_drop.rs +++ b/library/core/src/future/async_drop.rs @@ -133,9 +133,8 @@ pub trait AsyncDrop { } #[lang = "async_destruct"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] trait AsyncDestruct { type AsyncDestructor: Future; } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 7d44ea7a66ba5..7b31bbec7547c 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1382,22 +1382,10 @@ pub unsafe fn prefetch_write_instruction(_data: *const T, _locality: i32) { #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -#[cfg(not(bootstrap))] pub fn breakpoint() { unreachable!() } -/// Executes a breakpoint trap, for inspection by a debugger. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -#[cfg(bootstrap)] -pub unsafe fn breakpoint() { - unreachable!() -} - /// Magic intrinsic that derives its meaning from attributes /// attached to the function. /// @@ -3323,8 +3311,8 @@ pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_const_unstable(feature = "const_carrying_mul_add", issue = "85532")] #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] -#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] pub const fn carrying_mul_add, U>( multiplier: T, multiplicand: T, @@ -3969,21 +3957,6 @@ pub const fn is_val_statically_known(_arg: T) -> bool { false } -#[rustc_nounwind] -#[inline] -#[rustc_intrinsic] -#[rustc_intrinsic_const_stable_indirect] -#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic -#[cfg(bootstrap)] -pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { - // SAFETY: The caller provided single non-overlapping items behind - // pointers, so swapping them with `count: 1` is fine. - unsafe { ptr::swap_nonoverlapping(x, y, 1) }; -} - -#[cfg(bootstrap)] -pub use typed_swap as typed_swap_nonoverlapping; - /// Non-overlapping *typed* swap of a single value. /// /// The codegen backends will replace this with a better implementation when @@ -3999,7 +3972,6 @@ pub use typed_swap as typed_swap_nonoverlapping; #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic -#[cfg(not(bootstrap))] pub const unsafe fn typed_swap_nonoverlapping(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind // pointers, so swapping them with `count: 1` is fine. diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index f80a60d471c04..d03d801b93652 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -623,7 +623,6 @@ extern "rust-intrinsic" { /// and others do not. /// /// `T` must be a vector of floats. - #[cfg(not(bootstrap))] #[rustc_nounwind] pub fn simd_relaxed_fma(x: T, y: T, z: T) -> T; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e31957a1fa703..e845bb34426c4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,7 +107,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 29fc01d37fe3f..b1e67e4e90017 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -141,9 +141,8 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] #[rustc_coinductive] pub trait Sized { // Empty. @@ -183,9 +182,8 @@ pub trait Sized { /// [^1]: Formerly known as *object safe*. #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait Unsize { // Empty. } @@ -819,9 +817,8 @@ impl StructuralPartialEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -962,10 +959,9 @@ marker_impls! { #[unstable(feature = "const_destruct", issue = "133214")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] -#[cfg_attr(not(bootstrap), const_trait)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] +#[const_trait] pub trait Destruct {} /// A marker for tuple types. @@ -975,9 +971,8 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait Tuple {} /// A marker for pointer-like types. @@ -996,10 +991,9 @@ pub trait Tuple {} message = "`{Self}` needs to have the same ABI as a pointer", label = "`{Self}` needs to be a pointer-like type" )] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_do_not_implement_via_object] pub trait PointerLike {} -#[cfg(not(bootstrap))] marker_impls! { #[unstable(feature = "pointer_like_trait", issue = "none")] PointerLike for @@ -1086,9 +1080,8 @@ marker_impls! { reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait FnPtr: Copy + Clone { /// Returns the address of the function pointer. #[lang = "fn_ptr_addr"] @@ -1099,7 +1092,6 @@ pub trait FnPtr: Copy + Clone { #[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] -#[cfg(not(bootstrap))] pub macro CoercePointee($item:item) { /* compiler built-in */ } diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 9cf587650d949..6a4f84c849cb1 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -84,9 +84,8 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// `usize` is stable, but not portable. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] #[rustc_coinductive] pub unsafe trait TransmuteFrom where diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 565bccf589826..810b906b8715e 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -73,7 +73,7 @@ append_const_msg )] #[doc(alias = "+")] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -95,18 +95,6 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(bootstrap)] - impl Add for $t { - type Output = $t; - - #[inline] - #[track_caller] - #[rustc_inherit_overflow_checks] - fn add(self, other: $t) -> $t { self + other } - } - - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(bootstrap))] impl const Add for $t { type Output = $t; diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 2ee243ea85eb4..c90ae7babbd93 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -4,8 +4,7 @@ use crate::marker::Tuple; /// An async-aware version of the [`Fn`](crate::ops::Fn) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -19,8 +18,7 @@ pub trait AsyncFn: AsyncFnMut { /// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -41,8 +39,7 @@ pub trait AsyncFnMut: AsyncFnOnce { /// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -67,8 +64,7 @@ mod impls { use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; use crate::marker::Tuple; - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl AsyncFn for &F where F: AsyncFn, @@ -78,8 +74,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl AsyncFnMut for &F where F: AsyncFn, @@ -94,8 +89,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F where F: AsyncFn, @@ -108,8 +102,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl AsyncFnMut for &mut F where F: AsyncFnMut, @@ -124,8 +117,7 @@ mod impls { } } - #[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] - #[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] + #[stable(feature = "async_closure", since = "1.85.0")] impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F where F: AsyncFnMut, diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index c36d55fe2a8c1..ed0d30a0f5026 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -133,7 +133,7 @@ #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -148,18 +148,6 @@ pub trait Deref { fn deref(&self) -> &Self::Target; } -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for &T { - type Target = T; - - #[rustc_diagnostic_item = "noop_method_deref"] - fn deref(&self) -> &T { - *self - } -} - -#[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl const Deref for &T { type Target = T; @@ -173,17 +161,6 @@ impl const Deref for &T { #[stable(feature = "rust1", since = "1.0.0")] impl !DerefMut for &T {} -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for &mut T { - type Target = T; - - fn deref(&self) -> &T { - *self - } -} - -#[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl const Deref for &mut T { type Target = T; @@ -282,7 +259,6 @@ impl const Deref for &mut T { /// *x = 'b'; /// assert_eq!('b', x.value); /// ``` -#[cfg(not(bootstrap))] #[lang = "deref_mut"] #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] @@ -294,27 +270,6 @@ pub trait DerefMut: ~const Deref { fn deref_mut(&mut self) -> &mut Self::Target; } -/// Bootstrap -#[lang = "deref_mut"] -#[doc(alias = "*")] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg(bootstrap)] -pub trait DerefMut: Deref { - /// Mutably dereferences the value. - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_diagnostic_item = "deref_mut_method"] - fn deref_mut(&mut self) -> &mut Self::Target; -} - -#[cfg(bootstrap)] -#[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for &mut T { - fn deref_mut(&mut self) -> &mut T { - *self - } -} - -#[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl const DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index f3314364e5428..78b5252195f82 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -203,7 +203,7 @@ /// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Drop { /// Executes the destructor for this type. /// diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index b1d5e1fa3a059..e93b5658e2436 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -53,9 +53,8 @@ use crate::ptr::NonNull; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))] -#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] -#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 21bde4b8cc1fb..7af26d521b3ff 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1556,7 +1556,6 @@ impl DispatchFromDyn> for NonNull where T: U unsafe impl PinCoerceUnsized for NonNull {} #[unstable(feature = "pointer_like_trait", issue = "none")] -#[cfg(not(bootstrap))] impl core::marker::PointerLike for NonNull {} #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index e6825d8e39e2c..7cefb615d0371 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -304,7 +304,7 @@ fn test_const_nonnull_new() { #[test] #[cfg(unix)] // printf may not be available on other platforms #[allow(deprecated)] // For SipHasher -#[cfg_attr(not(bootstrap), allow(unpredictable_function_pointer_comparisons))] +#[allow(unpredictable_function_pointer_comparisons)] pub fn test_variadic_fnptr() { use core::ffi; use core::hash::{Hash, SipHasher}; diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index 713e417e0440c..0f2d8334fca79 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -12,8 +12,7 @@ pub use crate::marker::{Send, Sized, Sync, Unpin}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; -#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] -#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "1.85.0"))] +#[stable(feature = "async_closure", since = "1.85.0")] #[doc(no_inline)] pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 432fbb8d63682..c121543462cf2 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -624,8 +624,6 @@ impl Builder<'_> { // get warnings about it being unexpected. hostflags.arg("-Zunstable-options"); hostflags.arg("--check-cfg=cfg(bootstrap)"); - // #[cfg(bootstrap)] as we are transition `test` to userspace cfg - hostflags.arg("--check-cfg=cfg(test)"); // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`, // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See @@ -1206,10 +1204,7 @@ impl Builder<'_> { // so that it'll be available when downstream consumers of std try to use it. rustflags.arg("-Zinline-mir-preserve-debug"); - // FIXME: always pass this after the next `#[cfg(bootstrap)]` update. - if compiler.stage != 0 { - rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions"); - } + rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions"); } Cargo { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 8405c22aff08f..4cc812829f9b6 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -77,8 +77,6 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; #[allow(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above. const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ (None, "bootstrap", None), - // #[cfg(bootstrap)] to be removed when Cargo is updated - (None, "test", None), (Some(Mode::Rustc), "llvm_enzyme", None), (Some(Mode::Codegen), "llvm_enzyme", None), (Some(Mode::ToolRustc), "llvm_enzyme", None), From a7f84e981e0b73f7bc061ea584949b7aca02502b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 21:34:57 +0100 Subject: [PATCH 122/189] applease clippy --- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 4 ++-- src/bootstrap/src/core/build_steps/dist.rs | 4 ++-- src/bootstrap/src/core/build_steps/install.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/core/config/config.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 7fd811ac5071d..46fad688ebaa0 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -344,7 +344,7 @@ impl Step for RustAnalyzer { .config .tools .as_ref() - .map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")), + .is_none_or(|tools| tools.iter().any(|tool| tool == "rust-analyzer")), ) } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index b4c56df6ea6df..2dc3873569e5b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1673,10 +1673,10 @@ impl Step for Sysroot { ]; let ci_rustc_dir = builder.config.ci_rustc_dir(); builder.cp_link_filtered(&ci_rustc_dir, &sysroot, &|path| { - if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) { + if path.extension().is_none_or(|ext| !filtered_extensions.contains(&ext)) { return true; } - if !path.parent().map_or(true, |p| p.ends_with(&suffix)) { + if !path.parent().is_none_or(|p| p.ends_with(&suffix)) { return true; } if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) { diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 8bfa9cc94b341..29bc0cbf58a89 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -47,7 +47,7 @@ fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool { if !builder.config.extended { return false; } - builder.config.tools.as_ref().map_or(true, |tools| tools.contains(tool)) + builder.config.tools.as_ref().is_none_or(|tools| tools.contains(tool)) } #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] @@ -410,7 +410,7 @@ impl Step for Rustc { .config .tools .as_ref() - .map_or(true, |tools| tools.iter().any(|tool| tool == "rustdoc")) + .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc")) { let rustdoc = builder.rustdoc(compiler); builder.install(&rustdoc, &image.join("bin"), 0o755); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index b6862c2d5c4a9..3ee95475e3aed 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -307,7 +307,7 @@ impl Step for Src { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let config = &run.builder.config; - let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src")); + let cond = config.extended && config.tools.as_ref().is_none_or(|t|t.contains("src")); run.path("src").default_condition(cond) } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index da2ce5b59763d..3d01647aacc61 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1443,7 +1443,7 @@ impl<'a> Builder<'a> { let mut stack = self.stack.borrow_mut(); for stack_step in stack.iter() { // should skip - if stack_step.downcast_ref::().map_or(true, |stack_step| *stack_step != step) { + if stack_step.downcast_ref::().is_none_or(|stack_step| *stack_step != step) { continue; } let mut out = String::new(); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index dd2f11ad4690a..acabfc3685e02 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1125,7 +1125,7 @@ impl<'de> Deserialize<'de> for LldMode { match v { "external" => Ok(LldMode::External), "self-contained" => Ok(LldMode::SelfContained), - _ => Err(E::custom("unknown mode {v}")), + _ => Err(E::custom(format!("unknown mode {v}"))), } } } From d894ce8827a65e06e96200482fad9e54dbdd17a6 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 8 Jan 2025 22:11:33 +0100 Subject: [PATCH 123/189] fmt --- library/core/src/hash/mod.rs | 5 +---- library/std/src/collections/hash/map.rs | 5 +---- library/std/src/collections/hash/set.rs | 5 +---- src/bootstrap/src/core/build_steps/install.rs | 2 +- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index b43cf68421594..7a6630c82d0da 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -753,10 +753,7 @@ pub struct BuildHasherDefault(marker::PhantomData H>); impl BuildHasherDefault { /// Creates a new BuildHasherDefault for Hasher `H`. #[stable(feature = "build_hasher_default_const_new", since = "1.85.0")] - #[rustc_const_stable( - feature = "build_hasher_default_const_new", - since = "1.85.0" - )] + #[rustc_const_stable(feature = "build_hasher_default_const_new", since = "1.85.0")] pub const fn new() -> Self { BuildHasherDefault(marker::PhantomData) } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index f7d2eec90743c..d2342d8fd5176 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -296,10 +296,7 @@ impl HashMap { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_stable( - feature = "const_collections_with_hasher", - since = "1.85.0" - )] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hash_builder: S) -> HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index c1b794c58f120..bbb6ca2352136 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -388,10 +388,7 @@ impl HashSet { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_stable( - feature = "const_collections_with_hasher", - since = "1.85.0" - )] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hasher: S) -> HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } } diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 3ee95475e3aed..4f96d67a5bd89 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -307,7 +307,7 @@ impl Step for Src { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let config = &run.builder.config; - let cond = config.extended && config.tools.as_ref().is_none_or(|t|t.contains("src")); + let cond = config.extended && config.tools.as_ref().is_none_or(|t| t.contains("src")); run.path("src").default_condition(cond) } From eb917ea24deeeb92ab76fcb215aac4c7a567644d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2025 21:18:46 +0000 Subject: [PATCH 124/189] Remove some unnecessary `.into()` calls --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 6 +++--- compiler/rustc_parse/src/parser/tests.rs | 6 ++---- .../rustc_trait_selection/src/traits/const_evaluatable.rs | 4 ++-- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- library/std/src/thread/mod.rs | 2 +- 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 81a5e9ee90d72..dd6adb17c5e47 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1120,7 +1120,7 @@ fn check_type_defn<'tcx>( } else { // Evaluate the constant proactively, to emit an error if the constant has // an unconditional error. We only do so if the const has no type params. - let _ = tcx.const_eval_poly(def_id.into()); + let _ = tcx.const_eval_poly(def_id); } } let field_id = field.did.expect_local(); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e74fb9d92e9e0..31ba8619c36d3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1304,9 +1304,9 @@ impl UnreachablePub { cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| { effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable) }) - && let parent_parent = cx.tcx.parent_module_from_def_id( - cx.tcx.parent_module_from_def_id(def_id.into()).into(), - ) + && let parent_parent = cx + .tcx + .parent_module_from_def_id(cx.tcx.parent_module_from_def_id(def_id).into()) && *restricted_did == parent_parent.to_local_def_id() && !restricted_did.to_def_id().is_crate_root() { diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 3f8d66c2c9580..b810bb4e3bbd9 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2366,8 +2366,7 @@ fn string_to_tts_1() { token::Ident(sym::i32, IdentIsRaw::No), sp(8, 11), ), - ]) - .into(), + ]), ), TokenTree::Delimited( DelimSpan::from_pair(sp(13, 14), sp(18, 19)), @@ -2383,8 +2382,7 @@ fn string_to_tts_1() { ), // `Alone` because the `;` is followed by whitespace. TokenTree::token_alone(token::Semi, sp(16, 17)), - ]) - .into(), + ]), ), ]); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 15eb5d74cbfa5..446f9eaa348c0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -79,7 +79,7 @@ pub fn is_const_evaluatable<'tcx>( Err( EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e), - ) => Err(NotConstEvaluatable::Error(e.into())), + ) => Err(NotConstEvaluatable::Error(e)), Ok(_) => Ok(()), } } @@ -140,7 +140,7 @@ pub fn is_const_evaluatable<'tcx>( } Err( EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e), - ) => Err(NotConstEvaluatable::Error(e.into())), + ) => Err(NotConstEvaluatable::Error(e)), Ok(_) => Ok(()), } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e014404eff35b..08a7b32579868 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1789,7 +1789,7 @@ impl Rc { /// let x: Rc<&str> = Rc::new("Hello, world!"); /// { /// let s = String::from("Oh, no!"); - /// let mut y: Rc<&str> = x.clone().into(); + /// let mut y: Rc<&str> = x.clone(); /// unsafe { /// // this is Undefined Behavior, because x's inner type /// // is &'long str, not &'short str diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b34a6d3f660c8..30761739dbff2 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2468,7 +2468,7 @@ impl Arc { /// let x: Arc<&str> = Arc::new("Hello, world!"); /// { /// let s = String::from("Oh, no!"); - /// let mut y: Arc<&str> = x.clone().into(); + /// let mut y: Arc<&str> = x.clone(); /// unsafe { /// // this is Undefined Behavior, because x's inner type /// // is &'long str, not &'short str diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 85ee369ca2b66..b6ee00a253a95 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -502,7 +502,7 @@ impl Builder { let id = ThreadId::new(); let my_thread = match name { - Some(name) => Thread::new(id, name.into()), + Some(name) => Thread::new(id, name), None => Thread::new_unnamed(id), }; From 933c4f5a811f2c73b82c35c5b759c2e6b0f5e2f0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 8 Jan 2025 10:26:24 +0000 Subject: [PATCH 125/189] Add a list of symbols for stable standard library crates There are a few locations where the crate name is checked against an enumerated list of `std`, `core`, `alloc`, and `proc_macro`, or some subset thereof. In most of these cases, all four crates should likely be treated the same. Change this so the crates are listed in one place, and that list is used wherever a list of `std` crates is needed. `test` could be considered relevant in some of these cases, but generally treating it separate from the others seems preferable while it is unstable. There are also a few places that Clippy will be able to use this. --- compiler/rustc_expand/src/config.rs | 17 +++++++---------- .../src/method/prelude_edition_lints.rs | 6 +++--- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_span/src/symbol.rs | 4 ++++ .../traits/fulfillment_errors.rs | 4 ++-- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 91624c7554cb0..3e3f35332e0d5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -18,7 +18,7 @@ use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; use rustc_session::Session; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; use thin_vec::ThinVec; use tracing::instrument; @@ -107,14 +107,11 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // If the enabled feature is unstable, record it. if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() { - // When the ICE comes from core, alloc or std (approximation of the standard - // library), there's a chance that the person hitting the ICE may be using - // -Zbuild-std or similar with an untested target. The bug is probably in the - // standard library and not the compiler in that case, but that doesn't really - // matter - we want a bug report. - if features.internal(name) - && ![sym::core, sym::alloc, sym::std].contains(&crate_name) - { + // When the ICE comes a standard library crate, there's a chance that the person + // hitting the ICE may be using -Zbuild-std or similar with an untested target. + // The bug is probably in the standard library and not the compiler in that case, + // but that doesn't really matter - we want a bug report. + if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } @@ -133,7 +130,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. - if features.internal(name) && ![sym::core, sym::alloc, sym::std].contains(&crate_name) { + if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 5ccfcf93f69ef..69d7a6c97cb36 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -8,7 +8,7 @@ use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty}; use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS}; -use rustc_span::{Ident, Span, kw, sym}; +use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; @@ -76,7 +76,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // No need to lint if method came from std/core, as that will now be in the prelude - if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { + if STDLIB_STABLE_CRATES.contains(&self.tcx.crate_name(pick.item.def_id.krate)) { return; } @@ -252,7 +252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // No need to lint if method came from std/core, as that will now be in the prelude - if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { + if STDLIB_STABLE_CRATES.contains(&self.tcx.crate_name(pick.item.def_id.krate)) { return; } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d5c2a337b4c19..51cfbf594716c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -67,7 +67,7 @@ mod span_encoding; pub use span_encoding::{DUMMY_SP, Span}; pub mod symbol; -pub use symbol::{Ident, MacroRulesNormalizedIdent, Symbol, kw, sym}; +pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym}; mod analyze_source_file; pub mod fatal_error; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0dcf38e349365..ef1e2c20978c4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2240,6 +2240,10 @@ symbols! { } } +/// Symbols for crates that are part of the stable standard library: `std`, `core`, `alloc`, and +/// `proc_macro`. +pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, sym::proc_macro]; + #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] pub struct Ident { pub name: Symbol, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 7ba87e180d0bc..405c26b5b3b58 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::{ self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::{debug, instrument}; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; @@ -520,7 +520,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { Some(macro_def_id) => { let crate_name = tcx.crate_name(macro_def_id.krate); - crate_name == sym::std || crate_name == sym::core + STDLIB_STABLE_CRATES.contains(&crate_name) } None => false, }; From 72945beedd799c7debe0dddc14cc4e9a00943770 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 8 Jan 2025 17:58:34 -0800 Subject: [PATCH 126/189] Remove special-casing for argument patterns in MIR typeck --- compiler/rustc_borrowck/src/type_check/mod.rs | 13 ------------- .../lifetime-errors/ex3-both-anon-regions-2.rs | 2 +- .../lifetime-errors/ex3-both-anon-regions-2.stderr | 14 ++++++++------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 889b5684a2120..a1979c8b8aba1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -892,19 +892,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } - Some(_) - if let Some(body_id) = tcx - .hir_node_by_def_id(body.source.def_id().expect_local()) - .body_id() - && let params = tcx.hir().body(body_id).params - && params - .iter() - .any(|param| param.span.contains(stmt.source_info.span)) => - { - // Assignments generated from lowering argument patterns shouldn't be called - // "assignments" in diagnostics and aren't interesting to blame for errors. - ConstraintCategory::Boring - } _ => ConstraintCategory::Assignment, }; debug!( diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs index 09ee9accccd2f..66e6eb91a22e3 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs @@ -1,6 +1,6 @@ fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - *v = x; //~^ ERROR lifetime may not live long enough + *v = x; } fn main() { } diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr index 30083b5ef5462..e7cab52084ddd 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -1,13 +1,15 @@ error: lifetime may not live long enough - --> $DIR/ex3-both-anon-regions-2.rs:2:5 + --> $DIR/ex3-both-anon-regions-2.rs:1:14 | LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) { - | - - let's call the lifetime of this reference `'1` - | | - | let's call the lifetime of this reference `'2` -LL | *v = x; - | ^^^^^^ assignment requires that `'1` must outlive `'2` + | ^^^^^^^^^ - - let's call the lifetime of this reference `'1` + | | | + | | let's call the lifetime of this reference `'2` + | assignment requires that `'1` must outlive `'2` | + = note: requirement occurs because of a mutable reference to `&u8` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance help: consider introducing a named lifetime parameter | LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) { From 8dcc676c9283b040d1ef6d66f156ff2212544b10 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 21 Nov 2024 17:59:43 -0800 Subject: [PATCH 127/189] [mir-opt] GVN some more transmute cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already did `Transmute`-then-`PtrToPtr`; this adds the nearly-identical `PtrToPtr`-then-`Transmute`. It also adds `transmute(Foo(x))` → `transmute(x)`, when `Foo` is a single-field transparent type. That's useful for things like `NonNull { pointer: p }.as_ptr()`. Found these as I was looking at MCP807-related changes. --- compiler/rustc_mir_transform/src/gvn.rs | 56 +++++- .../rustc_mir_transform/src/instsimplify.rs | 23 --- ...n.DataflowConstProp.32bit.panic-abort.diff | 2 +- ....DataflowConstProp.32bit.panic-unwind.diff | 2 +- ...n.DataflowConstProp.64bit.panic-abort.diff | 2 +- ....DataflowConstProp.64bit.panic-unwind.diff | 2 +- ...oxed_slice.main.GVN.32bit.panic-abort.diff | 6 +- ...xed_slice.main.GVN.32bit.panic-unwind.diff | 6 +- ...oxed_slice.main.GVN.64bit.panic-abort.diff | 6 +- ...xed_slice.main.GVN.64bit.panic-unwind.diff | 6 +- ...struct_then_transmute.GVN.panic-abort.diff | 81 ++++++++ ...truct_then_transmute.GVN.panic-unwind.diff | 81 ++++++++ tests/mir-opt/gvn.rs | 50 ++++- ...ute_then_cast_pointer.GVN.panic-abort.diff | 115 +++++++++++ ...te_then_cast_pointer.GVN.panic-unwind.diff | 115 +++++++++++ .../inline_shims.drop.Inline.panic-abort.diff | 87 +++++++-- ...67_inline_as_ref_as_mut.b.Inline.after.mir | 2 +- ...67_inline_as_ref_as_mut.d.Inline.after.mir | 2 +- .../unsized_argument.caller.Inline.diff | 2 +- ...smutes.InstSimplify-after-simplifycfg.diff | 83 -------- ...nsmute.InstSimplify-after-simplifycfg.diff | 30 +++ .../instsimplify/combine_transmutes.rs | 25 ++- ...ated_loop.PreCodegen.after.panic-abort.mir | 182 +++++++++--------- ...ted_loop.PreCodegen.after.panic-unwind.mir | 132 ++++++------- ...ward_loop.PreCodegen.after.panic-abort.mir | 116 +++++------ ...ard_loop.PreCodegen.after.panic-unwind.mir | 116 +++++------ ...erse_loop.PreCodegen.after.panic-abort.mir | 130 ++++++------- ...rse_loop.PreCodegen.after.panic-unwind.mir | 130 ++++++------- ..._to_slice.PreCodegen.after.panic-abort.mir | 46 ++--- ...to_slice.PreCodegen.after.panic-unwind.mir | 46 ++--- 30 files changed, 1034 insertions(+), 648 deletions(-) create mode 100644 tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff create mode 100644 tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-unwind.diff delete mode 100644 tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify-after-simplifycfg.diff create mode 100644 tests/mir-opt/instsimplify/combine_transmutes.keep_transparent_transmute.InstSimplify-after-simplifycfg.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 283ed94b61513..ca70dc36da015 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1368,7 +1368,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let mut was_updated = false; - // If that cast just casts away the metadata again, + // Transmuting `*const T` <=> `*mut T` is just a pointer cast, + // which we might be able to merge with other ones later. + if let Transmute = kind + && let ty::RawPtr(from_pointee, _) = from.kind() + && let ty::RawPtr(to_pointee, _) = to.kind() + && from_pointee == to_pointee + { + *kind = PtrToPtr; + was_updated = true; + } + + // If a cast just casts away the metadata again, then we can get it by + // casting the original thin pointer passed to `from_raw_parts` if let PtrToPtr = kind && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = self.get(value) @@ -1397,6 +1409,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + // Aggregate-then-Transmute can just transmute the original field value, + // so long as the type is transparent over only that one single field. + if let Transmute = kind + && let Value::Aggregate( + AggregateTy::Def(aggregate_did, aggregate_args), + FIRST_VARIANT, + field_values, + ) = self.get(value) + && let [single_field_value] = **field_values + && let adt = self.tcx.adt_def(aggregate_did) + && adt.is_struct() + && adt.repr().transparent() + { + let field_ty = adt.non_enum_variant().single_field().ty(self.tcx, aggregate_args); + from = field_ty; + value = single_field_value; + was_updated = true; + if field_ty == to { + return Some(single_field_value); + } + } + // PtrToPtr-then-Transmute can just transmute the original, so long as the // PtrToPtr didn't change metadata (and thus the size of the pointer) if let Transmute = kind @@ -1416,6 +1450,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + // PtrToPtr-then-Transmute can just transmute the original, so long as the + // PtrToPtr didn't change metadata (and thus the size of the pointer) + if let PtrToPtr = kind + && let Value::Cast { + kind: Transmute, + value: inner_value, + from: inner_from, + to: _inner_to, + } = *self.get(value) + && self.pointers_have_same_metadata(from, to) + { + *kind = Transmute; + from = inner_from; + value = inner_value; + was_updated = true; + if inner_from == to { + return Some(inner_value); + } + } + if was_updated && let Some(op) = self.try_as_operand(value, location) { *operand = op; } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 1a65affe8121a..9e024508c5828 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -173,29 +173,6 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { *kind = CastKind::IntToInt; return; } - - // Transmuting a transparent struct/union to a field's type is a projection - if let ty::Adt(adt_def, args) = operand_ty.kind() - && adt_def.repr().transparent() - && (adt_def.is_struct() || adt_def.is_union()) - && let Some(place) = operand.place() - { - let variant = adt_def.non_enum_variant(); - for (i, field) in variant.fields.iter_enumerated() { - let field_ty = field.ty(self.tcx, args); - if field_ty == *cast_ty { - let place = place - .project_deeper(&[ProjectionElem::Field(i, *cast_ty)], self.tcx); - let operand = if operand.is_move() { - Operand::Move(place) - } else { - Operand::Copy(place) - }; - *rvalue = Rvalue::Use(operand); - return; - } - } - } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 4097e060f4d47..5ea9902b26251 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -51,7 +51,6 @@ StorageLive(_7); _7 = const 1_usize; _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -79,6 +78,7 @@ _11 = const {0x1 as *const [bool; 0]}; _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index ff44d0df5e3e9..cc5a41a7f63b1 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -51,7 +51,6 @@ StorageLive(_7); _7 = const 1_usize; _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -83,6 +82,7 @@ _11 = const {0x1 as *const [bool; 0]}; _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 3662c3b59d271..3d398fbea7935 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -51,7 +51,6 @@ StorageLive(_7); _7 = const 1_usize; _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -79,6 +78,7 @@ _11 = const {0x1 as *const [bool; 0]}; _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 68dee57dee9e0..dc99c3f7a8c9b 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -51,7 +51,6 @@ StorageLive(_7); _7 = const 1_usize; _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -83,6 +82,7 @@ _11 = const {0x1 as *const [bool; 0]}; _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff index e62fcb66e3a6d..6a3ec54306994 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff @@ -53,7 +53,6 @@ - _6 = copy _7 as *mut [bool; 0] (Transmute); + _7 = const 1_usize; + _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -67,7 +66,7 @@ bb2: { StorageLive(_10); -- _10 = copy _6 as *mut () (PtrToPtr); +- _10 = copy _7 as *mut () (Transmute); - _9 = NonNull::::new_unchecked::precondition_check(move _10) -> [return: bb3, unwind unreachable]; + _10 = const {0x1 as *mut ()}; + _9 = NonNull::::new_unchecked::precondition_check(const {0x1 as *mut ()}) -> [return: bb3, unwind unreachable]; @@ -80,11 +79,12 @@ bb4: { StorageDead(_8); -- _11 = copy _6 as *const [bool; 0] (PtrToPtr); +- _11 = copy _7 as *const [bool; 0] (Transmute); - _5 = NonNull::<[bool; 0]> { pointer: copy _11 }; + _11 = const {0x1 as *const [bool; 0]}; + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); - _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff index 8183abd315ae5..9471ad47cd9df 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff @@ -53,7 +53,6 @@ - _6 = copy _7 as *mut [bool; 0] (Transmute); + _7 = const 1_usize; + _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -71,7 +70,7 @@ bb3: { StorageLive(_10); -- _10 = copy _6 as *mut () (PtrToPtr); +- _10 = copy _7 as *mut () (Transmute); - _9 = NonNull::::new_unchecked::precondition_check(move _10) -> [return: bb4, unwind unreachable]; + _10 = const {0x1 as *mut ()}; + _9 = NonNull::::new_unchecked::precondition_check(const {0x1 as *mut ()}) -> [return: bb4, unwind unreachable]; @@ -84,11 +83,12 @@ bb5: { StorageDead(_8); -- _11 = copy _6 as *const [bool; 0] (PtrToPtr); +- _11 = copy _7 as *const [bool; 0] (Transmute); - _5 = NonNull::<[bool; 0]> { pointer: copy _11 }; + _11 = const {0x1 as *const [bool; 0]}; + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); - _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff index 4fa6ef29e0697..187927b8ecab7 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff @@ -53,7 +53,6 @@ - _6 = copy _7 as *mut [bool; 0] (Transmute); + _7 = const 1_usize; + _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -67,7 +66,7 @@ bb2: { StorageLive(_10); -- _10 = copy _6 as *mut () (PtrToPtr); +- _10 = copy _7 as *mut () (Transmute); - _9 = NonNull::::new_unchecked::precondition_check(move _10) -> [return: bb3, unwind unreachable]; + _10 = const {0x1 as *mut ()}; + _9 = NonNull::::new_unchecked::precondition_check(const {0x1 as *mut ()}) -> [return: bb3, unwind unreachable]; @@ -80,11 +79,12 @@ bb4: { StorageDead(_8); -- _11 = copy _6 as *const [bool; 0] (PtrToPtr); +- _11 = copy _7 as *const [bool; 0] (Transmute); - _5 = NonNull::<[bool; 0]> { pointer: copy _11 }; + _11 = const {0x1 as *const [bool; 0]}; + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); - _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff index 753292045632f..031c021ba5abf 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff @@ -53,7 +53,6 @@ - _6 = copy _7 as *mut [bool; 0] (Transmute); + _7 = const 1_usize; + _6 = const {0x1 as *mut [bool; 0]}; - StorageDead(_7); StorageLive(_11); StorageLive(_8); _8 = UbChecks(); @@ -71,7 +70,7 @@ bb3: { StorageLive(_10); -- _10 = copy _6 as *mut () (PtrToPtr); +- _10 = copy _7 as *mut () (Transmute); - _9 = NonNull::::new_unchecked::precondition_check(move _10) -> [return: bb4, unwind unreachable]; + _10 = const {0x1 as *mut ()}; + _9 = NonNull::::new_unchecked::precondition_check(const {0x1 as *mut ()}) -> [return: bb4, unwind unreachable]; @@ -84,11 +83,12 @@ bb5: { StorageDead(_8); -- _11 = copy _6 as *const [bool; 0] (PtrToPtr); +- _11 = copy _7 as *const [bool; 0] (Transmute); - _5 = NonNull::<[bool; 0]> { pointer: copy _11 }; + _11 = const {0x1 as *const [bool; 0]}; + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_11); + StorageDead(_7); StorageDead(_6); - _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff new file mode 100644 index 0000000000000..161141ebc6447 --- /dev/null +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff @@ -0,0 +1,81 @@ +- // MIR for `aggregate_struct_then_transmute` before GVN ++ // MIR for `aggregate_struct_then_transmute` after GVN + + fn aggregate_struct_then_transmute(_1: u16) -> () { + debug id => _1; + let mut _0: (); + let _2: MyId; + let mut _3: u16; + let _4: (); + let mut _5: u16; + let mut _6: MyId; + let mut _8: u16; + let mut _9: std::marker::PhantomData; + let _10: (); + let mut _11: u16; + let mut _12: TypedId; + scope 1 { + debug a => _2; + let _7: TypedId; + scope 2 { + debug b => _7; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = copy _1; +- _2 = MyId(move _3); ++ _2 = MyId(copy _1); + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = move _2; +- _5 = move _6 as u16 (Transmute); ++ _6 = copy _2; ++ _5 = copy _1; + StorageDead(_6); +- _4 = opaque::(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = opaque::(copy _1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_5); + StorageDead(_4); +- StorageLive(_7); ++ nop; + StorageLive(_8); + _8 = copy _1; + StorageLive(_9); +- _9 = PhantomData::; +- _7 = TypedId::(move _8, move _9); ++ _9 = const PhantomData::; ++ _7 = TypedId::(copy _1, const PhantomData::); + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); +- _12 = move _7; +- _11 = move _12 as u16 (Transmute); ++ _12 = copy _7; ++ _11 = copy _7 as u16 (Transmute); + StorageDead(_12); + _10 = opaque::(move _11) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_11); + StorageDead(_10); + _0 = const (); +- StorageDead(_7); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..a9d9f2c82c839 --- /dev/null +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff @@ -0,0 +1,81 @@ +- // MIR for `aggregate_struct_then_transmute` before GVN ++ // MIR for `aggregate_struct_then_transmute` after GVN + + fn aggregate_struct_then_transmute(_1: u16) -> () { + debug id => _1; + let mut _0: (); + let _2: MyId; + let mut _3: u16; + let _4: (); + let mut _5: u16; + let mut _6: MyId; + let mut _8: u16; + let mut _9: std::marker::PhantomData; + let _10: (); + let mut _11: u16; + let mut _12: TypedId; + scope 1 { + debug a => _2; + let _7: TypedId; + scope 2 { + debug b => _7; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = copy _1; +- _2 = MyId(move _3); ++ _2 = MyId(copy _1); + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = move _2; +- _5 = move _6 as u16 (Transmute); ++ _6 = copy _2; ++ _5 = copy _1; + StorageDead(_6); +- _4 = opaque::(move _5) -> [return: bb1, unwind continue]; ++ _4 = opaque::(copy _1) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_5); + StorageDead(_4); +- StorageLive(_7); ++ nop; + StorageLive(_8); + _8 = copy _1; + StorageLive(_9); +- _9 = PhantomData::; +- _7 = TypedId::(move _8, move _9); ++ _9 = const PhantomData::; ++ _7 = TypedId::(copy _1, const PhantomData::); + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); +- _12 = move _7; +- _11 = move _12 as u16 (Transmute); ++ _12 = copy _7; ++ _11 = copy _7 as u16 (Transmute); + StorageDead(_12); + _10 = opaque::(move _11) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_11); + StorageDead(_10); + _0 = const (); +- StorageDead(_7); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 19b58a917f87c..5fc252de0e5c5 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -12,7 +12,7 @@ #![allow(unused)] use std::intrinsics::mir::*; -use std::marker::Freeze; +use std::marker::{Freeze, PhantomData}; use std::mem::transmute; struct S(T); @@ -933,6 +933,20 @@ fn cast_pointer_eq(p1: *mut u8, p2: *mut u32, p3: *mut u32, p4: *mut [u32]) { // CHECK: _0 = const (); } +unsafe fn aggregate_struct_then_transmute(id: u16) { + // CHECK: opaque::(copy _1) + let a = MyId(id); + opaque(std::intrinsics::transmute::<_, u16>(a)); + + // GVN can't do this yet because it doesn't know which field is the ZST, + // but future changes might enable it. + // CHECK: [[AGG:_.+]] = TypedId::(copy _1, const PhantomData::); + // CHECK: [[INT:_.+]] = copy [[AGG]] as u16 (Transmute); + // CHECK: opaque::(move [[INT]]) + let b = TypedId::(id, PhantomData); + opaque(std::intrinsics::transmute::<_, u16>(b)); +} + // Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast. unsafe fn cast_pointer_then_transmute(thin: *mut u32, fat: *mut [u8]) { // CHECK-LABEL: fn cast_pointer_then_transmute @@ -946,6 +960,28 @@ unsafe fn cast_pointer_then_transmute(thin: *mut u32, fat: *mut [u8]) { let fat_addr: usize = std::intrinsics::transmute(fat as *const ()); } +unsafe fn transmute_then_cast_pointer(addr: usize, fat: *mut [u8]) { + // CHECK-LABEL: fn transmute_then_cast_pointer + + // This is roughly what `NonNull::dangling` does + // CHECK: [[CPTR:_.+]] = copy _1 as *const u8 (Transmute); + // CHECK: takes_const_ptr::(move [[CPTR]]) + let p: *mut u8 = std::intrinsics::transmute(addr); + takes_const_ptr(p); + + // This cast is fat-to-thin, so can't be merged with the transmute + // CHECK: [[FAT:_.+]] = move {{.+}} as *const [i32] (Transmute); + // CHECK: [[THIN:_.+]] = copy [[FAT]] as *const i32 (PtrToPtr); + // CHECK: takes_const_ptr::(move [[THIN]]) + let q = std::intrinsics::transmute::<&mut [i32], *const [i32]>(&mut [1, 2, 3]); + takes_const_ptr(q as *const i32); + + // CHECK: [[TPTR:_.+]] = copy _2 as *const u8 (PtrToPtr); + // CHECK: takes_const_ptr::(move [[TPTR]]) + let w = std::intrinsics::transmute::<*mut [u8], *const [u8]>(fat); + takes_const_ptr(w as *const u8); +} + #[custom_mir(dialect = "analysis")] fn remove_casts_must_change_both_sides(mut_a: &*mut u8, mut_b: *mut u8) -> bool { // CHECK-LABEL: fn remove_casts_must_change_both_sides( @@ -1002,6 +1038,16 @@ fn identity(x: T) -> T { x } +#[inline(never)] +fn takes_const_ptr(_: *const T) {} + +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_end(55555)] +struct MyId(u16); + +#[repr(transparent)] +struct TypedId(u16, PhantomData); + // EMIT_MIR gvn.subexpression_elimination.GVN.diff // EMIT_MIR gvn.wrap_unwrap.GVN.diff // EMIT_MIR gvn.repeated_index.GVN.diff @@ -1034,5 +1080,7 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.dedup_multiple_bounds_checks_lengths.GVN.diff // EMIT_MIR gvn.generic_cast_metadata.GVN.diff // EMIT_MIR gvn.cast_pointer_eq.GVN.diff +// EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff // EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff +// EMIT_MIR gvn.transmute_then_cast_pointer.GVN.diff // EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff diff --git a/tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-abort.diff b/tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-abort.diff new file mode 100644 index 0000000000000..0bec425dd9957 --- /dev/null +++ b/tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-abort.diff @@ -0,0 +1,115 @@ +- // MIR for `transmute_then_cast_pointer` before GVN ++ // MIR for `transmute_then_cast_pointer` after GVN + + fn transmute_then_cast_pointer(_1: usize, _2: *mut [u8]) -> () { + debug addr => _1; + debug fat => _2; + let mut _0: (); + let _3: *mut u8; + let mut _4: usize; + let _5: (); + let mut _6: *const u8; + let mut _7: *mut u8; + let mut _9: &mut [i32]; + let mut _10: &mut [i32; 3]; + let mut _11: &mut [i32; 3]; + let mut _12: [i32; 3]; + let _13: (); + let mut _14: *const i32; + let mut _15: *const [i32]; + let mut _17: *mut [u8]; + let _18: (); + let mut _19: *const u8; + let mut _20: *const [u8]; + scope 1 { + debug p => _3; + let _8: *const [i32]; + scope 2 { + debug q => _8; + let _16: *const [u8]; + scope 3 { + debug w => _16; + } + } + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as *mut u8 (Transmute); ++ _3 = copy _1 as *mut u8 (Transmute); + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _3; +- _6 = move _7 as *const u8 (PtrToPtr); ++ _6 = copy _1 as *const u8 (Transmute); + StorageDead(_7); + _5 = takes_const_ptr::(move _6) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_6); + StorageDead(_5); +- StorageLive(_8); ++ nop; + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); + _12 = [const 1_i32, const 2_i32, const 3_i32]; + _11 = &mut _12; + _10 = &mut (*_11); + _9 = move _10 as &mut [i32] (PointerCoercion(Unsize, Implicit)); + StorageDead(_10); + _8 = move _9 as *const [i32] (Transmute); + StorageDead(_9); + StorageDead(_12); + StorageDead(_11); + StorageLive(_13); + StorageLive(_14); + StorageLive(_15); + _15 = copy _8; +- _14 = move _15 as *const i32 (PtrToPtr); ++ _14 = copy _8 as *const i32 (PtrToPtr); + StorageDead(_15); + _13 = takes_const_ptr::(move _14) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_14); + StorageDead(_13); +- StorageLive(_16); ++ nop; + StorageLive(_17); + _17 = copy _2; +- _16 = move _17 as *const [u8] (Transmute); ++ _16 = copy _2 as *const [u8] (PtrToPtr); + StorageDead(_17); + StorageLive(_18); + StorageLive(_19); + StorageLive(_20); + _20 = copy _16; +- _19 = move _20 as *const u8 (PtrToPtr); ++ _19 = copy _2 as *const u8 (PtrToPtr); + StorageDead(_20); + _18 = takes_const_ptr::(move _19) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_19); + StorageDead(_18); + _0 = const (); +- StorageDead(_16); +- StorageDead(_8); +- StorageDead(_3); ++ nop; ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-unwind.diff b/tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..14f2fe08a86a2 --- /dev/null +++ b/tests/mir-opt/gvn.transmute_then_cast_pointer.GVN.panic-unwind.diff @@ -0,0 +1,115 @@ +- // MIR for `transmute_then_cast_pointer` before GVN ++ // MIR for `transmute_then_cast_pointer` after GVN + + fn transmute_then_cast_pointer(_1: usize, _2: *mut [u8]) -> () { + debug addr => _1; + debug fat => _2; + let mut _0: (); + let _3: *mut u8; + let mut _4: usize; + let _5: (); + let mut _6: *const u8; + let mut _7: *mut u8; + let mut _9: &mut [i32]; + let mut _10: &mut [i32; 3]; + let mut _11: &mut [i32; 3]; + let mut _12: [i32; 3]; + let _13: (); + let mut _14: *const i32; + let mut _15: *const [i32]; + let mut _17: *mut [u8]; + let _18: (); + let mut _19: *const u8; + let mut _20: *const [u8]; + scope 1 { + debug p => _3; + let _8: *const [i32]; + scope 2 { + debug q => _8; + let _16: *const [u8]; + scope 3 { + debug w => _16; + } + } + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as *mut u8 (Transmute); ++ _3 = copy _1 as *mut u8 (Transmute); + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _3; +- _6 = move _7 as *const u8 (PtrToPtr); ++ _6 = copy _1 as *const u8 (Transmute); + StorageDead(_7); + _5 = takes_const_ptr::(move _6) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_6); + StorageDead(_5); +- StorageLive(_8); ++ nop; + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); + _12 = [const 1_i32, const 2_i32, const 3_i32]; + _11 = &mut _12; + _10 = &mut (*_11); + _9 = move _10 as &mut [i32] (PointerCoercion(Unsize, Implicit)); + StorageDead(_10); + _8 = move _9 as *const [i32] (Transmute); + StorageDead(_9); + StorageDead(_12); + StorageDead(_11); + StorageLive(_13); + StorageLive(_14); + StorageLive(_15); + _15 = copy _8; +- _14 = move _15 as *const i32 (PtrToPtr); ++ _14 = copy _8 as *const i32 (PtrToPtr); + StorageDead(_15); + _13 = takes_const_ptr::(move _14) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_14); + StorageDead(_13); +- StorageLive(_16); ++ nop; + StorageLive(_17); + _17 = copy _2; +- _16 = move _17 as *const [u8] (Transmute); ++ _16 = copy _2 as *const [u8] (PtrToPtr); + StorageDead(_17); + StorageLive(_18); + StorageLive(_19); + StorageLive(_20); + _20 = copy _16; +- _19 = move _20 as *const u8 (PtrToPtr); ++ _19 = copy _2 as *const u8 (PtrToPtr); + StorageDead(_20); + _18 = takes_const_ptr::(move _19) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_19); + StorageDead(_18); + _0 = const (); +- StorageDead(_16); +- StorageDead(_8); +- StorageDead(_3); ++ nop; ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 581244074b36c..4337e0da18336 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -11,10 +11,43 @@ + scope 1 (inlined std::ptr::drop_in_place::> - shim(Some(Vec))) { + let mut _6: &mut std::vec::Vec; + let mut _7: (); ++ scope 2 (inlined as Drop>::drop) { ++ let mut _8: *mut [A]; ++ let mut _9: *mut A; ++ let mut _10: usize; ++ scope 3 (inlined Vec::::as_mut_ptr) { ++ scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { ++ scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { ++ scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { ++ let mut _11: std::ptr::NonNull; ++ scope 7 (inlined Unique::::cast::) { ++ scope 8 (inlined NonNull::::cast::) { ++ scope 9 (inlined NonNull::::as_ptr) { ++ } ++ } ++ } ++ scope 10 (inlined Unique::::as_non_null_ptr) { ++ } ++ } ++ scope 11 (inlined NonNull::::as_ptr) { ++ } ++ } ++ } ++ } ++ scope 12 (inlined slice_from_raw_parts_mut::) { ++ scope 13 (inlined std::ptr::from_raw_parts_mut::<[A], A>) { ++ } ++ } ++ scope 14 (inlined std::ptr::drop_in_place::<[A]> - shim(Some([A]))) { ++ let mut _12: usize; ++ let mut _13: *mut A; ++ let mut _14: bool; ++ } ++ } + } -+ scope 2 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { -+ let mut _8: isize; -+ let mut _9: isize; ++ scope 15 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { ++ let mut _15: isize; ++ let mut _16: isize; + } bb0: { @@ -25,7 +58,21 @@ + StorageLive(_6); + StorageLive(_7); + _6 = &mut (*_4); -+ _7 = as Drop>::drop(move _6) -> [return: bb2, unwind unreachable]; ++ StorageLive(_10); ++ StorageLive(_8); ++ StorageLive(_9); ++ StorageLive(_11); ++ _11 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); ++ _9 = copy _11 as *mut A (Transmute); ++ StorageDead(_11); ++ _10 = copy ((*_6).1: usize); ++ _8 = *mut [A] from (copy _9, copy _10); ++ StorageDead(_9); ++ StorageLive(_12); ++ StorageLive(_13); ++ StorageLive(_14); ++ _12 = const 0_usize; ++ goto -> bb4; } bb1: { @@ -36,25 +83,41 @@ StorageLive(_5); _5 = copy _2; - _0 = std::ptr::drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; -+ StorageLive(_8); -+ StorageLive(_9); -+ _8 = discriminant((*_5)); -+ switchInt(move _8) -> [0: bb3, otherwise: bb4]; ++ StorageLive(_15); ++ StorageLive(_16); ++ _15 = discriminant((*_5)); ++ switchInt(move _15) -> [0: bb5, otherwise: bb6]; } bb2: { ++ StorageDead(_14); ++ StorageDead(_13); ++ StorageDead(_12); ++ StorageDead(_8); ++ StorageDead(_10); + drop(((*_4).0: alloc::raw_vec::RawVec)) -> [return: bb1, unwind unreachable]; + } + + bb3: { -+ StorageDead(_9); -+ StorageDead(_8); ++ _13 = &raw mut (*_8)[_12]; ++ _12 = Add(move _12, const 1_usize); ++ drop((*_13)) -> [return: bb4, unwind unreachable]; ++ } ++ ++ bb4: { ++ _14 = Eq(copy _12, copy _10); ++ switchInt(move _14) -> [0: bb3, otherwise: bb2]; ++ } ++ ++ bb5: { ++ StorageDead(_16); ++ StorageDead(_15); StorageDead(_5); return; + } + -+ bb4: { -+ drop((((*_5) as Some).0: B)) -> [return: bb3, unwind unreachable]; ++ bb6: { ++ drop((((*_5) as Some).0: B)) -> [return: bb5, unwind unreachable]; } } diff --git a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 02aadfc1de064..103475b608cee 100644 --- a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -20,7 +20,7 @@ fn b(_1: &mut Box) -> &mut T { StorageLive(_5); StorageLive(_6); _5 = copy (*_4); - _6 = copy (((_5.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const T); + _6 = copy ((_5.0: std::ptr::Unique).0: std::ptr::NonNull) as *const T (Transmute); _3 = &mut (*_6); StorageDead(_6); StorageDead(_5); diff --git a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index 1ea347510fdb4..babb26808cece 100644 --- a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -18,7 +18,7 @@ fn d(_1: &Box) -> &T { StorageLive(_4); StorageLive(_5); _4 = copy (*_3); - _5 = copy (((_4.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const T); + _5 = copy ((_4.0: std::ptr::Unique).0: std::ptr::NonNull) as *const T (Transmute); _2 = &(*_5); StorageDead(_5); StorageDead(_4); diff --git a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff index 70671e2089a01..644d6d320de04 100644 --- a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff +++ b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff @@ -12,7 +12,7 @@ StorageLive(_2); StorageLive(_3); _3 = move _1; - _4 = copy (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); + _4 = copy ((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>) as *const [i32] (Transmute); _2 = callee(move (*_4)) -> [return: bb1, unwind: bb3]; } diff --git a/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify-after-simplifycfg.diff deleted file mode 100644 index 9844aa2a64e26..0000000000000 --- a/tests/mir-opt/instsimplify/combine_transmutes.adt_transmutes.InstSimplify-after-simplifycfg.diff +++ /dev/null @@ -1,83 +0,0 @@ -- // MIR for `adt_transmutes` before InstSimplify-after-simplifycfg -+ // MIR for `adt_transmutes` after InstSimplify-after-simplifycfg - - fn adt_transmutes() -> () { - let mut _0: (); - let _1: u8; - let mut _2: std::option::Option>; - let mut _4: std::num::Wrapping; - let mut _6: std::num::Wrapping; - let mut _8: Union32; - let mut _10: Union32; - let mut _12: std::mem::MaybeUninit; - scope 1 { - debug _a => _1; - let _3: i16; - scope 2 { - debug _a => _3; - let _5: u16; - scope 3 { - debug _a => _5; - let _7: u32; - scope 4 { - debug _a => _7; - let _9: i32; - scope 5 { - debug _a => _9; - let _11: std::mem::ManuallyDrop; - scope 6 { - debug _a => _11; - } - } - } - } - } - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - _2 = Option::>::Some(const std::num::NonZero::::MAX); - _1 = move _2 as u8 (Transmute); - StorageDead(_2); - StorageLive(_3); - StorageLive(_4); - _4 = Wrapping::(const 0_i16); -- _3 = move _4 as i16 (Transmute); -+ _3 = move (_4.0: i16); - StorageDead(_4); - StorageLive(_5); - StorageLive(_6); - _6 = Wrapping::(const 0_i16); - _5 = move _6 as u16 (Transmute); - StorageDead(_6); - StorageLive(_7); - StorageLive(_8); - _8 = Union32 { u32: const 0_i32 }; - _7 = move _8 as u32 (Transmute); - StorageDead(_8); - StorageLive(_9); - StorageLive(_10); - _10 = Union32 { u32: const 0_u32 }; - _9 = move _10 as i32 (Transmute); - StorageDead(_10); - StorageLive(_11); - StorageLive(_12); - _12 = MaybeUninit::::uninit() -> [return: bb1, unwind unreachable]; - } - - bb1: { -- _11 = move _12 as std::mem::ManuallyDrop (Transmute); -+ _11 = move (_12.1: std::mem::ManuallyDrop); - StorageDead(_12); - _0 = const (); - StorageDead(_11); - StorageDead(_9); - StorageDead(_7); - StorageDead(_5); - StorageDead(_3); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/instsimplify/combine_transmutes.keep_transparent_transmute.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/combine_transmutes.keep_transparent_transmute.InstSimplify-after-simplifycfg.diff new file mode 100644 index 0000000000000..66a29629591ad --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_transmutes.keep_transparent_transmute.InstSimplify-after-simplifycfg.diff @@ -0,0 +1,30 @@ +- // MIR for `keep_transparent_transmute` before InstSimplify-after-simplifycfg ++ // MIR for `keep_transparent_transmute` after InstSimplify-after-simplifycfg + + fn keep_transparent_transmute() -> () { + let mut _0: (); + let _1: i16; + let mut _3: std::num::Wrapping; + scope 1 { + debug _a => _1; + let _2: i16; + scope 2 { + debug _a => _2; + } + } + + bb0: { + StorageLive(_1); + _1 = const keep_transparent_transmute::{constant#0} as i16 (Transmute); + StorageLive(_2); + StorageLive(_3); + _3 = Wrapping::(const 0_i16); + _2 = move _3 as i16 (Transmute); + StorageDead(_3); + _0 = const (); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_transmutes.rs b/tests/mir-opt/instsimplify/combine_transmutes.rs index 8a670301825be..c12f307ca0e5a 100644 --- a/tests/mir-opt/instsimplify/combine_transmutes.rs +++ b/tests/mir-opt/instsimplify/combine_transmutes.rs @@ -43,22 +43,19 @@ pub unsafe fn integer_transmutes() { } } -// EMIT_MIR combine_transmutes.adt_transmutes.InstSimplify-after-simplifycfg.diff -pub unsafe fn adt_transmutes() { - // CHECK-LABEL: fn adt_transmutes( - // CHECK: as u8 (Transmute); - // CHECK: ({{_.*}}.0: i16); - // CHECK: as u16 (Transmute); - // CHECK: as u32 (Transmute); - // CHECK: as i32 (Transmute); - // CHECK: ({{_.*}}.1: std::mem::ManuallyDrop); +// EMIT_MIR combine_transmutes.keep_transparent_transmute.InstSimplify-after-simplifycfg.diff +pub unsafe fn keep_transparent_transmute() { + // CHECK-LABEL: fn keep_transparent_transmute( + // CHECK-NOT: .{{[0-9]+}}: i16 + // CHECK: as i16 (Transmute); + // CHECK-NOT: .{{[0-9]+}}: i16 + // CHECK: as i16 (Transmute); + // CHECK-NOT: .{{[0-9]+}}: i16 - let _a: u8 = transmute(Some(std::num::NonZero::::MAX)); + // Transmutes should not be converted to field accesses, because MCP#807 + // bans projections into `[rustc_layout_scalar_valid_range_*]` types. + let _a: i16 = transmute(const { std::num::NonZero::new(12345_i16).unwrap() }); let _a: i16 = transmute(std::num::Wrapping(0_i16)); - let _a: u16 = transmute(std::num::Wrapping(0_i16)); - let _a: u32 = transmute(Union32 { i32: 0 }); - let _a: i32 = transmute(Union32 { u32: 0 }); - let _a: ManuallyDrop = transmute(MaybeUninit::::uninit()); } pub union Union32 { diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index a3308cc5df196..9494b8a2addb1 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -4,28 +4,28 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _13: std::slice::Iter<'_, T>; - let mut _14: std::iter::Enumerate>; - let mut _15: std::iter::Enumerate>; - let mut _23: std::option::Option<(usize, &T)>; - let mut _26: &impl Fn(usize, &T); - let mut _27: (usize, &T); - let _28: (); + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Enumerate>; + let mut _13: std::iter::Enumerate>; + let mut _21: std::option::Option<(usize, &T)>; + let mut _24: &impl Fn(usize, &T); + let mut _25: (usize, &T); + let _26: (); scope 1 { - debug iter => _15; - let _24: usize; - let _25: &T; + debug iter => _13; + let _22: usize; + let _23: &T; scope 2 { - debug i => _24; - debug x => _25; + debug i => _22; + debug x => _23; } scope 18 (inlined > as Iterator>::next) { - let mut _16: &mut std::slice::Iter<'_, T>; - let mut _17: std::option::Option<&T>; - let mut _21: (usize, bool); - let mut _22: (usize, &T); + let mut _14: &mut std::slice::Iter<'_, T>; + let mut _15: std::option::Option<&T>; + let mut _19: (usize, bool); + let mut _20: (usize, &T); scope 19 { - let _20: usize; + let _18: usize; scope 24 { } } @@ -40,8 +40,8 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 25 (inlined as Try>::branch) { - let mut _18: isize; - let _19: &T; + let mut _16: isize; + let _17: &T; scope 26 { } } @@ -50,14 +50,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 3 (inlined core::slice::::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _5: std::ptr::NonNull<[T]>; - let mut _9: *mut T; - let mut _10: *mut T; - let mut _12: *const T; + let mut _7: *mut T; + let mut _8: *mut T; + let mut _10: *const T; scope 5 { - let _8: std::ptr::NonNull; + let _6: std::ptr::NonNull; scope 6 { - let _11: *const T; + let _9: *const T; scope 7 { } scope 12 (inlined without_provenance::) { @@ -73,8 +72,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 10 (inlined NonNull::<[T]>::cast::) { - let mut _6: *mut [T]; - let mut _7: *const T; + let mut _5: *const T; scope 11 (inlined NonNull::<[T]>::as_ptr) { } } @@ -89,82 +87,74 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - StorageLive(_13); + StorageLive(_11); StorageLive(_3); - StorageLive(_8); - _3 = PtrMetadata(copy _1); + StorageLive(_6); StorageLive(_5); - StorageLive(_4); + _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); - _5 = NonNull::<[T]> { pointer: move _4 }; - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _6 = copy _5 as *mut [T] (Transmute); - _7 = copy _6 as *const T (PtrToPtr); - _8 = NonNull:: { pointer: move _7 }; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); - StorageLive(_11); + _5 = copy _4 as *const T (PtrToPtr); + _6 = NonNull:: { pointer: copy _5 }; + StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_9); - _9 = copy _8 as *mut T (Transmute); - _10 = Offset(copy _9, copy _3); - StorageDead(_9); - _11 = move _10 as *const T (PtrToPtr); - StorageDead(_10); + StorageLive(_8); + StorageLive(_7); + _7 = copy _4 as *mut T (PtrToPtr); + _8 = Offset(copy _7, copy _3); + StorageDead(_7); + _9 = move _8 as *const T (PtrToPtr); + StorageDead(_8); goto -> bb3; } bb2: { - _11 = copy _3 as *const T (Transmute); + _9 = copy _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageLive(_12); - _12 = copy _11; - _13 = std::slice::Iter::<'_, T> { ptr: copy _8, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_12); - StorageDead(_11); - StorageDead(_8); + StorageLive(_10); + _10 = copy _9; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + StorageDead(_10); + StorageDead(_9); + StorageDead(_5); + StorageDead(_6); StorageDead(_3); - _14 = Enumerate::> { iter: copy _13, count: const 0_usize }; - StorageDead(_13); - StorageLive(_15); - _15 = copy _14; + _12 = Enumerate::> { iter: copy _11, count: const 0_usize }; + StorageDead(_11); + StorageLive(_13); + _13 = copy _12; goto -> bb4; } bb4: { - StorageLive(_23); - StorageLive(_20); StorageLive(_21); - StorageLive(_17); - StorageLive(_16); - _16 = &mut (_15.0: std::slice::Iter<'_, T>); - _17 = as Iterator>::next(move _16) -> [return: bb5, unwind unreachable]; + StorageLive(_18); + StorageLive(_19); + StorageLive(_15); + StorageLive(_14); + _14 = &mut (_13.0: std::slice::Iter<'_, T>); + _15 = as Iterator>::next(move _14) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_16); - StorageLive(_18); - _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb11]; + StorageDead(_14); + StorageLive(_16); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb11]; } bb6: { + StorageDead(_16); + StorageDead(_15); + StorageDead(_19); StorageDead(_18); - StorageDead(_17); StorageDead(_21); - StorageDead(_20); - StorageDead(_23); - StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -173,35 +163,35 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _19 = move ((_17 as Some).0: &T); - StorageDead(_18); - StorageDead(_17); - _20 = copy (_15.1: usize); - _21 = AddWithOverflow(copy (_15.1: usize), const 1_usize); - assert(!move (_21.1: bool), "attempt to compute `{} + {}`, which would overflow", copy (_15.1: usize), const 1_usize) -> [success: bb9, unwind unreachable]; + _17 = move ((_15 as Some).0: &T); + StorageDead(_16); + StorageDead(_15); + _18 = copy (_13.1: usize); + _19 = AddWithOverflow(copy (_13.1: usize), const 1_usize); + assert(!move (_19.1: bool), "attempt to compute `{} + {}`, which would overflow", copy (_13.1: usize), const 1_usize) -> [success: bb9, unwind unreachable]; } bb9: { - (_15.1: usize) = move (_21.0: usize); - StorageLive(_22); - _22 = (copy _20, copy _19); - _23 = Option::<(usize, &T)>::Some(move _22); - StorageDead(_22); - StorageDead(_21); + (_13.1: usize) = move (_19.0: usize); + StorageLive(_20); + _20 = (copy _18, copy _17); + _21 = Option::<(usize, &T)>::Some(move _20); StorageDead(_20); - _24 = copy (((_23 as Some).0: (usize, &T)).0: usize); - _25 = copy (((_23 as Some).0: (usize, &T)).1: &T); - StorageLive(_26); - _26 = &_2; - StorageLive(_27); - _27 = (copy _24, copy _25); - _28 = >::call(move _26, move _27) -> [return: bb10, unwind unreachable]; + StorageDead(_19); + StorageDead(_18); + _22 = copy (((_21 as Some).0: (usize, &T)).0: usize); + _23 = copy (((_21 as Some).0: (usize, &T)).1: &T); + StorageLive(_24); + _24 = &_2; + StorageLive(_25); + _25 = (copy _22, copy _23); + _26 = >::call(move _24, move _25) -> [return: bb10, unwind unreachable]; } bb10: { - StorageDead(_27); - StorageDead(_26); - StorageDead(_23); + StorageDead(_25); + StorageDead(_24); + StorageDead(_21); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 2a837fabd4c24..c9b9798bf33f3 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -4,35 +4,34 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _13: std::slice::Iter<'_, T>; - let mut _14: std::iter::Enumerate>; - let mut _15: std::iter::Enumerate>; - let mut _16: &mut std::iter::Enumerate>; - let mut _17: std::option::Option<(usize, &T)>; - let mut _18: isize; - let mut _21: &impl Fn(usize, &T); - let mut _22: (usize, &T); - let _23: (); + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Enumerate>; + let mut _13: std::iter::Enumerate>; + let mut _14: &mut std::iter::Enumerate>; + let mut _15: std::option::Option<(usize, &T)>; + let mut _16: isize; + let mut _19: &impl Fn(usize, &T); + let mut _20: (usize, &T); + let _21: (); scope 1 { - debug iter => _15; - let _19: usize; - let _20: &T; + debug iter => _13; + let _17: usize; + let _18: &T; scope 2 { - debug i => _19; - debug x => _20; + debug i => _17; + debug x => _18; } } scope 3 (inlined core::slice::::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _5: std::ptr::NonNull<[T]>; - let mut _9: *mut T; - let mut _10: *mut T; - let mut _12: *const T; + let mut _7: *mut T; + let mut _8: *mut T; + let mut _10: *const T; scope 5 { - let _8: std::ptr::NonNull; + let _6: std::ptr::NonNull; scope 6 { - let _11: *const T; + let _9: *const T; scope 7 { } scope 12 (inlined without_provenance::) { @@ -48,8 +47,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 10 (inlined NonNull::<[T]>::cast::) { - let mut _6: *mut [T]; - let mut _7: *const T; + let mut _5: *const T; scope 11 (inlined NonNull::<[T]>::as_ptr) { } } @@ -64,72 +62,64 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - StorageLive(_13); + StorageLive(_11); StorageLive(_3); - StorageLive(_8); - _3 = PtrMetadata(copy _1); + StorageLive(_6); StorageLive(_5); - StorageLive(_4); + _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); - _5 = NonNull::<[T]> { pointer: move _4 }; - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _6 = copy _5 as *mut [T] (Transmute); - _7 = copy _6 as *const T (PtrToPtr); - _8 = NonNull:: { pointer: move _7 }; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); - StorageLive(_11); + _5 = copy _4 as *const T (PtrToPtr); + _6 = NonNull:: { pointer: copy _5 }; + StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_9); - _9 = copy _8 as *mut T (Transmute); - _10 = Offset(copy _9, copy _3); - StorageDead(_9); - _11 = move _10 as *const T (PtrToPtr); - StorageDead(_10); + StorageLive(_8); + StorageLive(_7); + _7 = copy _4 as *mut T (PtrToPtr); + _8 = Offset(copy _7, copy _3); + StorageDead(_7); + _9 = move _8 as *const T (PtrToPtr); + StorageDead(_8); goto -> bb3; } bb2: { - _11 = copy _3 as *const T (Transmute); + _9 = copy _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageLive(_12); - _12 = copy _11; - _13 = std::slice::Iter::<'_, T> { ptr: copy _8, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_12); - StorageDead(_11); - StorageDead(_8); + StorageLive(_10); + _10 = copy _9; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + StorageDead(_10); + StorageDead(_9); + StorageDead(_5); + StorageDead(_6); StorageDead(_3); - _14 = Enumerate::> { iter: copy _13, count: const 0_usize }; - StorageDead(_13); - StorageLive(_15); - _15 = copy _14; + _12 = Enumerate::> { iter: copy _11, count: const 0_usize }; + StorageDead(_11); + StorageLive(_13); + _13 = copy _12; goto -> bb4; } bb4: { - StorageLive(_17); - _16 = &mut _15; - _17 = > as Iterator>::next(move _16) -> [return: bb5, unwind: bb11]; + StorageLive(_15); + _14 = &mut _13; + _15 = > as Iterator>::next(move _14) -> [return: bb5, unwind: bb11]; } bb5: { - _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10]; + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_17); StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind continue]; } @@ -138,19 +128,19 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _19 = copy (((_17 as Some).0: (usize, &T)).0: usize); - _20 = copy (((_17 as Some).0: (usize, &T)).1: &T); - StorageLive(_21); - _21 = &_2; - StorageLive(_22); - _22 = (copy _19, copy _20); - _23 = >::call(move _21, move _22) -> [return: bb9, unwind: bb11]; + _17 = copy (((_15 as Some).0: (usize, &T)).0: usize); + _18 = copy (((_15 as Some).0: (usize, &T)).1: &T); + StorageLive(_19); + _19 = &_2; + StorageLive(_20); + _20 = (copy _17, copy _18); + _21 = >::call(move _19, move _20) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_22); - StorageDead(_21); - StorageDead(_17); + StorageDead(_20); + StorageDead(_19); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 063045caebb5c..ac6fe0ac547ab 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -4,32 +4,31 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _13: std::slice::Iter<'_, T>; - let mut _14: std::slice::Iter<'_, T>; - let mut _15: &mut std::slice::Iter<'_, T>; - let mut _16: std::option::Option<&T>; - let mut _17: isize; - let mut _19: &impl Fn(&T); - let mut _20: (&T,); - let _21: (); + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::slice::Iter<'_, T>; + let mut _13: &mut std::slice::Iter<'_, T>; + let mut _14: std::option::Option<&T>; + let mut _15: isize; + let mut _17: &impl Fn(&T); + let mut _18: (&T,); + let _19: (); scope 1 { - debug iter => _14; - let _18: &T; + debug iter => _12; + let _16: &T; scope 2 { - debug x => _18; + debug x => _16; } } scope 3 (inlined core::slice::::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _5: std::ptr::NonNull<[T]>; - let mut _9: *mut T; - let mut _10: *mut T; - let mut _12: *const T; + let mut _7: *mut T; + let mut _8: *mut T; + let mut _10: *const T; scope 5 { - let _8: std::ptr::NonNull; + let _6: std::ptr::NonNull; scope 6 { - let _11: *const T; + let _9: *const T; scope 7 { } scope 12 (inlined without_provenance::) { @@ -45,8 +44,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 10 (inlined NonNull::<[T]>::cast::) { - let mut _6: *mut [T]; - let mut _7: *const T; + let mut _5: *const T; scope 11 (inlined NonNull::<[T]>::as_ptr) { } } @@ -58,68 +56,60 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb0: { StorageLive(_3); - StorageLive(_8); - _3 = PtrMetadata(copy _1); + StorageLive(_6); StorageLive(_5); - StorageLive(_4); + _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); - _5 = NonNull::<[T]> { pointer: move _4 }; - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _6 = copy _5 as *mut [T] (Transmute); - _7 = copy _6 as *const T (PtrToPtr); - _8 = NonNull:: { pointer: move _7 }; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); - StorageLive(_11); + _5 = copy _4 as *const T (PtrToPtr); + _6 = NonNull:: { pointer: copy _5 }; + StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_9); - _9 = copy _8 as *mut T (Transmute); - _10 = Offset(copy _9, copy _3); - StorageDead(_9); - _11 = move _10 as *const T (PtrToPtr); - StorageDead(_10); + StorageLive(_8); + StorageLive(_7); + _7 = copy _4 as *mut T (PtrToPtr); + _8 = Offset(copy _7, copy _3); + StorageDead(_7); + _9 = move _8 as *const T (PtrToPtr); + StorageDead(_8); goto -> bb3; } bb2: { - _11 = copy _3 as *const T (Transmute); + _9 = copy _3 as *const T (Transmute); goto -> bb3; } bb3: { + StorageLive(_10); + _10 = copy _9; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + StorageDead(_10); + StorageDead(_9); + StorageDead(_5); + StorageDead(_6); + StorageDead(_3); StorageLive(_12); _12 = copy _11; - _13 = std::slice::Iter::<'_, T> { ptr: copy _8, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_12); - StorageDead(_11); - StorageDead(_8); - StorageDead(_3); - StorageLive(_14); - _14 = copy _13; goto -> bb4; } bb4: { - StorageLive(_16); - _15 = &mut _14; - _16 = as Iterator>::next(move _15) -> [return: bb5, unwind unreachable]; + StorageLive(_14); + _13 = &mut _12; + _14 = as Iterator>::next(move _13) -> [return: bb5, unwind unreachable]; } bb5: { - _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_16); StorageDead(_14); + StorageDead(_12); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -128,18 +118,18 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _18 = copy ((_16 as Some).0: &T); - StorageLive(_19); - _19 = &_2; - StorageLive(_20); - _20 = (copy _18,); - _21 = >::call(move _19, move _20) -> [return: bb9, unwind unreachable]; + _16 = copy ((_14 as Some).0: &T); + StorageLive(_17); + _17 = &_2; + StorageLive(_18); + _18 = (copy _16,); + _19 = >::call(move _17, move _18) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_20); - StorageDead(_19); - StorageDead(_16); + StorageDead(_18); + StorageDead(_17); + StorageDead(_14); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index d401ed8fcf3ca..bc2403fc544a8 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -4,32 +4,31 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _13: std::slice::Iter<'_, T>; - let mut _14: std::slice::Iter<'_, T>; - let mut _15: &mut std::slice::Iter<'_, T>; - let mut _16: std::option::Option<&T>; - let mut _17: isize; - let mut _19: &impl Fn(&T); - let mut _20: (&T,); - let _21: (); + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::slice::Iter<'_, T>; + let mut _13: &mut std::slice::Iter<'_, T>; + let mut _14: std::option::Option<&T>; + let mut _15: isize; + let mut _17: &impl Fn(&T); + let mut _18: (&T,); + let _19: (); scope 1 { - debug iter => _14; - let _18: &T; + debug iter => _12; + let _16: &T; scope 2 { - debug x => _18; + debug x => _16; } } scope 3 (inlined core::slice::::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _5: std::ptr::NonNull<[T]>; - let mut _9: *mut T; - let mut _10: *mut T; - let mut _12: *const T; + let mut _7: *mut T; + let mut _8: *mut T; + let mut _10: *const T; scope 5 { - let _8: std::ptr::NonNull; + let _6: std::ptr::NonNull; scope 6 { - let _11: *const T; + let _9: *const T; scope 7 { } scope 12 (inlined without_provenance::) { @@ -45,8 +44,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 10 (inlined NonNull::<[T]>::cast::) { - let mut _6: *mut [T]; - let mut _7: *const T; + let mut _5: *const T; scope 11 (inlined NonNull::<[T]>::as_ptr) { } } @@ -58,68 +56,60 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb0: { StorageLive(_3); - StorageLive(_8); - _3 = PtrMetadata(copy _1); + StorageLive(_6); StorageLive(_5); - StorageLive(_4); + _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); - _5 = NonNull::<[T]> { pointer: move _4 }; - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _6 = copy _5 as *mut [T] (Transmute); - _7 = copy _6 as *const T (PtrToPtr); - _8 = NonNull:: { pointer: move _7 }; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); - StorageLive(_11); + _5 = copy _4 as *const T (PtrToPtr); + _6 = NonNull:: { pointer: copy _5 }; + StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_9); - _9 = copy _8 as *mut T (Transmute); - _10 = Offset(copy _9, copy _3); - StorageDead(_9); - _11 = move _10 as *const T (PtrToPtr); - StorageDead(_10); + StorageLive(_8); + StorageLive(_7); + _7 = copy _4 as *mut T (PtrToPtr); + _8 = Offset(copy _7, copy _3); + StorageDead(_7); + _9 = move _8 as *const T (PtrToPtr); + StorageDead(_8); goto -> bb3; } bb2: { - _11 = copy _3 as *const T (Transmute); + _9 = copy _3 as *const T (Transmute); goto -> bb3; } bb3: { + StorageLive(_10); + _10 = copy _9; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + StorageDead(_10); + StorageDead(_9); + StorageDead(_5); + StorageDead(_6); + StorageDead(_3); StorageLive(_12); _12 = copy _11; - _13 = std::slice::Iter::<'_, T> { ptr: copy _8, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_12); - StorageDead(_11); - StorageDead(_8); - StorageDead(_3); - StorageLive(_14); - _14 = copy _13; goto -> bb4; } bb4: { - StorageLive(_16); - _15 = &mut _14; - _16 = as Iterator>::next(move _15) -> [return: bb5, unwind: bb11]; + StorageLive(_14); + _13 = &mut _12; + _14 = as Iterator>::next(move _13) -> [return: bb5, unwind: bb11]; } bb5: { - _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_16); StorageDead(_14); + StorageDead(_12); drop(_2) -> [return: bb7, unwind continue]; } @@ -128,18 +118,18 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _18 = copy ((_16 as Some).0: &T); - StorageLive(_19); - _19 = &_2; - StorageLive(_20); - _20 = (copy _18,); - _21 = >::call(move _19, move _20) -> [return: bb9, unwind: bb11]; + _16 = copy ((_14 as Some).0: &T); + StorageLive(_17); + _17 = &_2; + StorageLive(_18); + _18 = (copy _16,); + _19 = >::call(move _17, move _18) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_20); - StorageDead(_19); - StorageDead(_16); + StorageDead(_18); + StorageDead(_17); + StorageDead(_14); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index deb12c4f1c22f..0eac3342ff73d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -4,35 +4,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _13: std::slice::Iter<'_, T>; - let mut _14: std::iter::Rev>; - let mut _15: std::iter::Rev>; - let mut _17: std::option::Option<&T>; - let mut _18: isize; - let mut _20: &impl Fn(&T); - let mut _21: (&T,); - let _22: (); + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Rev>; + let mut _13: std::iter::Rev>; + let mut _15: std::option::Option<&T>; + let mut _16: isize; + let mut _18: &impl Fn(&T); + let mut _19: (&T,); + let _20: (); scope 1 { - debug iter => _15; - let _19: &T; + debug iter => _13; + let _17: &T; scope 2 { - debug x => _19; + debug x => _17; } scope 18 (inlined > as Iterator>::next) { - let mut _16: &mut std::slice::Iter<'_, T>; + let mut _14: &mut std::slice::Iter<'_, T>; } } scope 3 (inlined core::slice::::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _5: std::ptr::NonNull<[T]>; - let mut _9: *mut T; - let mut _10: *mut T; - let mut _12: *const T; + let mut _7: *mut T; + let mut _8: *mut T; + let mut _10: *const T; scope 5 { - let _8: std::ptr::NonNull; + let _6: std::ptr::NonNull; scope 6 { - let _11: *const T; + let _9: *const T; scope 7 { } scope 12 (inlined without_provenance::) { @@ -48,8 +47,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 10 (inlined NonNull::<[T]>::cast::) { - let mut _6: *mut [T]; - let mut _7: *const T; + let mut _5: *const T; scope 11 (inlined NonNull::<[T]>::as_ptr) { } } @@ -64,74 +62,66 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb0: { - StorageLive(_13); + StorageLive(_11); StorageLive(_3); - StorageLive(_8); - _3 = PtrMetadata(copy _1); + StorageLive(_6); StorageLive(_5); - StorageLive(_4); + _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); - _5 = NonNull::<[T]> { pointer: move _4 }; - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _6 = copy _5 as *mut [T] (Transmute); - _7 = copy _6 as *const T (PtrToPtr); - _8 = NonNull:: { pointer: move _7 }; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); - StorageLive(_11); + _5 = copy _4 as *const T (PtrToPtr); + _6 = NonNull:: { pointer: copy _5 }; + StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_9); - _9 = copy _8 as *mut T (Transmute); - _10 = Offset(copy _9, copy _3); - StorageDead(_9); - _11 = move _10 as *const T (PtrToPtr); - StorageDead(_10); + StorageLive(_8); + StorageLive(_7); + _7 = copy _4 as *mut T (PtrToPtr); + _8 = Offset(copy _7, copy _3); + StorageDead(_7); + _9 = move _8 as *const T (PtrToPtr); + StorageDead(_8); goto -> bb3; } bb2: { - _11 = copy _3 as *const T (Transmute); + _9 = copy _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageLive(_12); - _12 = copy _11; - _13 = std::slice::Iter::<'_, T> { ptr: copy _8, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_12); - StorageDead(_11); - StorageDead(_8); + StorageLive(_10); + _10 = copy _9; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + StorageDead(_10); + StorageDead(_9); + StorageDead(_5); + StorageDead(_6); StorageDead(_3); - _14 = Rev::> { iter: copy _13 }; - StorageDead(_13); - StorageLive(_15); - _15 = copy _14; + _12 = Rev::> { iter: copy _11 }; + StorageDead(_11); + StorageLive(_13); + _13 = copy _12; goto -> bb4; } bb4: { - StorageLive(_17); - StorageLive(_16); - _16 = &mut (_15.0: std::slice::Iter<'_, T>); - _17 = as DoubleEndedIterator>::next_back(move _16) -> [return: bb5, unwind unreachable]; + StorageLive(_15); + StorageLive(_14); + _14 = &mut (_13.0: std::slice::Iter<'_, T>); + _15 = as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_16); - _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_14); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_17); StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -140,18 +130,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _19 = copy ((_17 as Some).0: &T); - StorageLive(_20); - _20 = &_2; - StorageLive(_21); - _21 = (copy _19,); - _22 = >::call(move _20, move _21) -> [return: bb9, unwind unreachable]; + _17 = copy ((_15 as Some).0: &T); + StorageLive(_18); + _18 = &_2; + StorageLive(_19); + _19 = (copy _17,); + _20 = >::call(move _18, move _19) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_21); - StorageDead(_20); - StorageDead(_17); + StorageDead(_19); + StorageDead(_18); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index acd5323eb7acd..376dc7163821a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -4,35 +4,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _13: std::slice::Iter<'_, T>; - let mut _14: std::iter::Rev>; - let mut _15: std::iter::Rev>; - let mut _17: std::option::Option<&T>; - let mut _18: isize; - let mut _20: &impl Fn(&T); - let mut _21: (&T,); - let _22: (); + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Rev>; + let mut _13: std::iter::Rev>; + let mut _15: std::option::Option<&T>; + let mut _16: isize; + let mut _18: &impl Fn(&T); + let mut _19: (&T,); + let _20: (); scope 1 { - debug iter => _15; - let _19: &T; + debug iter => _13; + let _17: &T; scope 2 { - debug x => _19; + debug x => _17; } scope 18 (inlined > as Iterator>::next) { - let mut _16: &mut std::slice::Iter<'_, T>; + let mut _14: &mut std::slice::Iter<'_, T>; } } scope 3 (inlined core::slice::::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _5: std::ptr::NonNull<[T]>; - let mut _9: *mut T; - let mut _10: *mut T; - let mut _12: *const T; + let mut _7: *mut T; + let mut _8: *mut T; + let mut _10: *const T; scope 5 { - let _8: std::ptr::NonNull; + let _6: std::ptr::NonNull; scope 6 { - let _11: *const T; + let _9: *const T; scope 7 { } scope 12 (inlined without_provenance::) { @@ -48,8 +47,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 10 (inlined NonNull::<[T]>::cast::) { - let mut _6: *mut [T]; - let mut _7: *const T; + let mut _5: *const T; scope 11 (inlined NonNull::<[T]>::as_ptr) { } } @@ -64,74 +62,66 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb0: { - StorageLive(_13); + StorageLive(_11); StorageLive(_3); - StorageLive(_8); - _3 = PtrMetadata(copy _1); + StorageLive(_6); StorageLive(_5); - StorageLive(_4); + _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); - _5 = NonNull::<[T]> { pointer: move _4 }; - StorageDead(_4); - StorageLive(_6); - StorageLive(_7); - _6 = copy _5 as *mut [T] (Transmute); - _7 = copy _6 as *const T (PtrToPtr); - _8 = NonNull:: { pointer: move _7 }; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); - StorageLive(_11); + _5 = copy _4 as *const T (PtrToPtr); + _6 = NonNull:: { pointer: copy _5 }; + StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_9); - _9 = copy _8 as *mut T (Transmute); - _10 = Offset(copy _9, copy _3); - StorageDead(_9); - _11 = move _10 as *const T (PtrToPtr); - StorageDead(_10); + StorageLive(_8); + StorageLive(_7); + _7 = copy _4 as *mut T (PtrToPtr); + _8 = Offset(copy _7, copy _3); + StorageDead(_7); + _9 = move _8 as *const T (PtrToPtr); + StorageDead(_8); goto -> bb3; } bb2: { - _11 = copy _3 as *const T (Transmute); + _9 = copy _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageLive(_12); - _12 = copy _11; - _13 = std::slice::Iter::<'_, T> { ptr: copy _8, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_12); - StorageDead(_11); - StorageDead(_8); + StorageLive(_10); + _10 = copy _9; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + StorageDead(_10); + StorageDead(_9); + StorageDead(_5); + StorageDead(_6); StorageDead(_3); - _14 = Rev::> { iter: copy _13 }; - StorageDead(_13); - StorageLive(_15); - _15 = copy _14; + _12 = Rev::> { iter: copy _11 }; + StorageDead(_11); + StorageLive(_13); + _13 = copy _12; goto -> bb4; } bb4: { - StorageLive(_17); - StorageLive(_16); - _16 = &mut (_15.0: std::slice::Iter<'_, T>); - _17 = as DoubleEndedIterator>::next_back(move _16) -> [return: bb5, unwind: bb11]; + StorageLive(_15); + StorageLive(_14); + _14 = &mut (_13.0: std::slice::Iter<'_, T>); + _15 = as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind: bb11]; } bb5: { - StorageDead(_16); - _18 = discriminant(_17); - switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_14); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_17); StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind continue]; } @@ -140,18 +130,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _19 = copy ((_17 as Some).0: &T); - StorageLive(_20); - _20 = &_2; - StorageLive(_21); - _21 = (copy _19,); - _22 = >::call(move _20, move _21) -> [return: bb9, unwind: bb11]; + _17 = copy ((_15 as Some).0: &T); + StorageLive(_18); + _18 = &_2; + StorageLive(_19); + _19 = (copy _17,); + _20 = >::call(move _18, move _19) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_21); - StorageDead(_20); - StorageDead(_17); + StorageDead(_19); + StorageDead(_18); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 3f0d60b46f48b..927deabd253f1 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -7,20 +7,16 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _7: *const u8; - let mut _8: usize; + let mut _3: *const u8; + let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _6: *mut u8; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { - let mut _5: std::ptr::NonNull; scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; scope 7 (inlined Unique::::cast::) { scope 8 (inlined NonNull::::cast::) { - let mut _3: *mut u8; - let mut _4: *const u8; scope 9 (inlined NonNull::::as_ptr) { } } @@ -34,9 +30,9 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _7; - debug len => _8; - let _9: *const [u8]; + debug data => _3; + debug len => _4; + let _5: *const [u8]; scope 13 (inlined core::ub_checks::check_language_ub) { scope 14 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -46,10 +42,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 16 (inlined align_of::) { } scope 17 (inlined slice_from_raw_parts::) { - debug data => _7; - debug len => _8; + debug data => _3; + debug len => _4; scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _7; + debug data_pointer => _3; } } } @@ -57,31 +53,19 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } bb0: { - StorageLive(_6); - StorageLive(_7); - StorageLive(_5); StorageLive(_2); - _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); StorageLive(_3); + _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _3 = copy _2 as *const u8 (Transmute); StorageLive(_4); - _3 = copy _2 as *mut u8 (Transmute); - _4 = copy _3 as *const u8 (PtrToPtr); - _5 = NonNull:: { pointer: move _4 }; + _4 = copy ((*_1).1: usize); + StorageLive(_5); + _5 = *const [u8] from (copy _3, copy _4); + _0 = &(*_5); + StorageDead(_5); StorageDead(_4); StorageDead(_3); StorageDead(_2); - _6 = copy _5 as *mut u8 (Transmute); - StorageDead(_5); - _7 = copy _6 as *const u8 (PtrToPtr); - StorageLive(_8); - _8 = copy ((*_1).1: usize); - StorageLive(_9); - _9 = *const [u8] from (copy _7, copy _8); - _0 = &(*_9); - StorageDead(_9); - StorageDead(_8); - StorageDead(_7); - StorageDead(_6); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 3f0d60b46f48b..927deabd253f1 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -7,20 +7,16 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _7: *const u8; - let mut _8: usize; + let mut _3: *const u8; + let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _6: *mut u8; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { - let mut _5: std::ptr::NonNull; scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; scope 7 (inlined Unique::::cast::) { scope 8 (inlined NonNull::::cast::) { - let mut _3: *mut u8; - let mut _4: *const u8; scope 9 (inlined NonNull::::as_ptr) { } } @@ -34,9 +30,9 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _7; - debug len => _8; - let _9: *const [u8]; + debug data => _3; + debug len => _4; + let _5: *const [u8]; scope 13 (inlined core::ub_checks::check_language_ub) { scope 14 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -46,10 +42,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 16 (inlined align_of::) { } scope 17 (inlined slice_from_raw_parts::) { - debug data => _7; - debug len => _8; + debug data => _3; + debug len => _4; scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _7; + debug data_pointer => _3; } } } @@ -57,31 +53,19 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } bb0: { - StorageLive(_6); - StorageLive(_7); - StorageLive(_5); StorageLive(_2); - _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); StorageLive(_3); + _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _3 = copy _2 as *const u8 (Transmute); StorageLive(_4); - _3 = copy _2 as *mut u8 (Transmute); - _4 = copy _3 as *const u8 (PtrToPtr); - _5 = NonNull:: { pointer: move _4 }; + _4 = copy ((*_1).1: usize); + StorageLive(_5); + _5 = *const [u8] from (copy _3, copy _4); + _0 = &(*_5); + StorageDead(_5); StorageDead(_4); StorageDead(_3); StorageDead(_2); - _6 = copy _5 as *mut u8 (Transmute); - StorageDead(_5); - _7 = copy _6 as *const u8 (PtrToPtr); - StorageLive(_8); - _8 = copy ((*_1).1: usize); - StorageLive(_9); - _9 = *const [u8] from (copy _7, copy _8); - _0 = &(*_9); - StorageDead(_9); - StorageDead(_8); - StorageDead(_7); - StorageDead(_6); return; } } From 259c425bd4a85e145b31021ce438727b1a201214 Mon Sep 17 00:00:00 2001 From: scottmcm Date: Sun, 8 Dec 2024 05:26:19 +0000 Subject: [PATCH 128/189] Apply suggestions from code review Co-authored-by: Oli Scherer --- compiler/rustc_mir_transform/src/gvn.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ca70dc36da015..ffbb054f84c4b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1450,8 +1450,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - // PtrToPtr-then-Transmute can just transmute the original, so long as the - // PtrToPtr didn't change metadata (and thus the size of the pointer) + // Transmute-then-PtrToPtr can just transmute the original, so long as the + // PtrToPtr won't change metadata (and thus the size of the pointer) if let PtrToPtr = kind && let Value::Cast { kind: Transmute, From 03650dd0290c3963dfd1f7f8e4325ccb7d3966f6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 7 Dec 2024 23:55:01 -0800 Subject: [PATCH 129/189] Use layout information to detect transparent transmutes --- compiler/rustc_mir_transform/src/gvn.rs | 43 +++++++++++++++---- ...struct_then_transmute.GVN.panic-abort.diff | 37 +++++++++++++++- ...truct_then_transmute.GVN.panic-unwind.diff | 37 +++++++++++++++- tests/mir-opt/gvn.rs | 12 +++--- 4 files changed, 111 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ffbb054f84c4b..0d2b4efe73911 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1410,24 +1410,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Aggregate-then-Transmute can just transmute the original field value, - // so long as the type is transparent over only that one single field. + // so long as the bytes of a value from only from a single field. if let Transmute = kind && let Value::Aggregate( AggregateTy::Def(aggregate_did, aggregate_args), - FIRST_VARIANT, + variant_idx, field_values, ) = self.get(value) - && let [single_field_value] = **field_values - && let adt = self.tcx.adt_def(aggregate_did) - && adt.is_struct() - && adt.repr().transparent() + && let aggregate_ty = + self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args) + && let Some((field_idx, field_ty)) = + self.value_is_all_in_one_field(aggregate_ty, *variant_idx) { - let field_ty = adt.non_enum_variant().single_field().ty(self.tcx, aggregate_args); from = field_ty; - value = single_field_value; + value = field_values[field_idx.as_usize()]; was_updated = true; if field_ty == to { - return Some(single_field_value); + return Some(value); } } @@ -1492,6 +1491,32 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { false } } + + fn value_is_all_in_one_field( + &self, + ty: Ty<'tcx>, + variant: VariantIdx, + ) -> Option<(FieldIdx, Ty<'tcx>)> { + if let Ok(layout) = self.ecx.layout_of(ty) + && let abi::Variants::Single { index } = layout.variants + && index == variant + && let Some((field_idx, field_layout)) = layout.non_1zst_field(&self.ecx) + && layout.size == field_layout.size + { + // We needed to check the variant to avoid trying to read the tag + // field from an enum where no fields have variants, since that tag + // field isn't in the `Aggregate` from which we're getting values. + Some((FieldIdx::from_usize(field_idx), field_layout.ty)) + } else if let ty::Adt(adt, args) = ty.kind() + && adt.is_struct() + && adt.repr().transparent() + && let [single_field] = adt.non_enum_variant().fields.raw.as_slice() + { + Some((FieldIdx::ZERO, single_field.ty(self.tcx, args))) + } else { + None + } + } } fn op_to_prop_const<'tcx>( diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff index 161141ebc6447..2b234637f4d93 100644 --- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff @@ -14,11 +14,19 @@ let _10: (); let mut _11: u16; let mut _12: TypedId; + let mut _14: u16; + let _15: (); + let mut _16: u16; + let mut _17: std::result::Result; scope 1 { debug a => _2; let _7: TypedId; scope 2 { debug b => _7; + let _13: std::result::Result; + scope 3 { + debug c => _13; + } } } @@ -62,18 +70,43 @@ - _12 = move _7; - _11 = move _12 as u16 (Transmute); + _12 = copy _7; -+ _11 = copy _7 as u16 (Transmute); ++ _11 = copy _1; StorageDead(_12); - _10 = opaque::(move _11) -> [return: bb2, unwind unreachable]; +- _10 = opaque::(move _11) -> [return: bb2, unwind unreachable]; ++ _10 = opaque::(copy _1) -> [return: bb2, unwind unreachable]; } bb2: { StorageDead(_11); StorageDead(_10); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = copy _1; +- _13 = Result::::Err(move _14); ++ _13 = Result::::Err(copy _1); + StorageDead(_14); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); +- _17 = move _13; +- _16 = move _17 as u16 (Transmute); ++ _17 = copy _13; ++ _16 = copy _1; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb3, unwind unreachable]; ++ _15 = opaque::(copy _1) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_16); + StorageDead(_15); _0 = const (); +- StorageDead(_13); - StorageDead(_7); - StorageDead(_2); + nop; ++ nop; + nop; return; } diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff index a9d9f2c82c839..2f36a3c393958 100644 --- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff @@ -14,11 +14,19 @@ let _10: (); let mut _11: u16; let mut _12: TypedId; + let mut _14: u16; + let _15: (); + let mut _16: u16; + let mut _17: std::result::Result; scope 1 { debug a => _2; let _7: TypedId; scope 2 { debug b => _7; + let _13: std::result::Result; + scope 3 { + debug c => _13; + } } } @@ -62,18 +70,43 @@ - _12 = move _7; - _11 = move _12 as u16 (Transmute); + _12 = copy _7; -+ _11 = copy _7 as u16 (Transmute); ++ _11 = copy _1; StorageDead(_12); - _10 = opaque::(move _11) -> [return: bb2, unwind continue]; +- _10 = opaque::(move _11) -> [return: bb2, unwind continue]; ++ _10 = opaque::(copy _1) -> [return: bb2, unwind continue]; } bb2: { StorageDead(_11); StorageDead(_10); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = copy _1; +- _13 = Result::::Err(move _14); ++ _13 = Result::::Err(copy _1); + StorageDead(_14); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); +- _17 = move _13; +- _16 = move _17 as u16 (Transmute); ++ _17 = copy _13; ++ _16 = copy _1; + StorageDead(_17); +- _15 = opaque::(move _16) -> [return: bb3, unwind continue]; ++ _15 = opaque::(copy _1) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_16); + StorageDead(_15); _0 = const (); +- StorageDead(_13); - StorageDead(_7); - StorageDead(_2); + nop; ++ nop; + nop; return; } diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 5fc252de0e5c5..3f9f0a0be37ce 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -938,13 +938,15 @@ unsafe fn aggregate_struct_then_transmute(id: u16) { let a = MyId(id); opaque(std::intrinsics::transmute::<_, u16>(a)); - // GVN can't do this yet because it doesn't know which field is the ZST, - // but future changes might enable it. - // CHECK: [[AGG:_.+]] = TypedId::(copy _1, const PhantomData::); - // CHECK: [[INT:_.+]] = copy [[AGG]] as u16 (Transmute); - // CHECK: opaque::(move [[INT]]) + // CHECK: opaque::(copy _1) let b = TypedId::(id, PhantomData); opaque(std::intrinsics::transmute::<_, u16>(b)); + + // CHECK: opaque::(copy _1) + let c = Err::(id); + opaque(std::intrinsics::transmute::<_, u16>(c)); + + enum Never {} } // Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast. From 293f8e8941e77c6372abd787fe564e9bf895445e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 5 Jan 2025 22:38:38 -0800 Subject: [PATCH 130/189] Refactor the cast-then-cast cases together, and support transmute-then-transmute --- compiler/rustc_mir_transform/src/gvn.rs | 202 ++++++++++-------- ...struct_then_transmute.GVN.panic-abort.diff | 131 +++++++++++- ...truct_then_transmute.GVN.panic-unwind.diff | 131 +++++++++++- tests/mir-opt/gvn.rs | 40 +++- ..._then_transmute_again.GVN.panic-abort.diff | 74 +++++++ ...then_transmute_again.GVN.panic-unwind.diff | 74 +++++++ ...ated_loop.PreCodegen.after.panic-abort.mir | 8 +- ...ted_loop.PreCodegen.after.panic-unwind.mir | 8 +- ...ward_loop.PreCodegen.after.panic-abort.mir | 8 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 8 +- ...erse_loop.PreCodegen.after.panic-abort.mir | 8 +- ...rse_loop.PreCodegen.after.panic-unwind.mir | 8 +- 12 files changed, 588 insertions(+), 112 deletions(-) create mode 100644 tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-abort.diff create mode 100644 tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 0d2b4efe73911..7c600fc1ceb2a 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1366,110 +1366,112 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return self.new_opaque(); } - let mut was_updated = false; - - // Transmuting `*const T` <=> `*mut T` is just a pointer cast, - // which we might be able to merge with other ones later. - if let Transmute = kind - && let ty::RawPtr(from_pointee, _) = from.kind() - && let ty::RawPtr(to_pointee, _) = to.kind() - && from_pointee == to_pointee - { - *kind = PtrToPtr; - was_updated = true; - } - - // If a cast just casts away the metadata again, then we can get it by - // casting the original thin pointer passed to `from_raw_parts` - if let PtrToPtr = kind - && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = - self.get(value) - && let ty::RawPtr(to_pointee, _) = to.kind() - && to_pointee.is_sized(self.tcx, self.typing_env()) - { - from = *data_pointer_ty; - value = fields[0]; - was_updated = true; - if *data_pointer_ty == to { - return Some(fields[0]); + let mut was_ever_updated = false; + loop { + let mut was_updated_this_iteration = false; + + // Transmuting `*const T` <=> `*mut T` is just a pointer cast, + // which we might be able to merge with other ones later. + if let Transmute = kind + && let ty::RawPtr(from_pointee, _) = from.kind() + && let ty::RawPtr(to_pointee, _) = to.kind() + && from_pointee == to_pointee + { + *kind = PtrToPtr; + was_updated_this_iteration = true; } - } - // PtrToPtr-then-PtrToPtr can skip the intermediate step - if let PtrToPtr = kind - && let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } = - *self.get(value) - && let PtrToPtr = inner_kind - { - from = inner_from; - value = inner_value; - was_updated = true; - if inner_from == to { - return Some(inner_value); + // If a cast just casts away the metadata again, then we can get it by + // casting the original thin pointer passed to `from_raw_parts` + if let PtrToPtr = kind + && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = + self.get(value) + && let ty::RawPtr(to_pointee, _) = to.kind() + && to_pointee.is_sized(self.tcx, self.typing_env()) + { + from = *data_pointer_ty; + value = fields[0]; + was_updated_this_iteration = true; + if *data_pointer_ty == to { + return Some(fields[0]); + } } - } - // Aggregate-then-Transmute can just transmute the original field value, - // so long as the bytes of a value from only from a single field. - if let Transmute = kind - && let Value::Aggregate( - AggregateTy::Def(aggregate_did, aggregate_args), - variant_idx, - field_values, - ) = self.get(value) - && let aggregate_ty = - self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args) - && let Some((field_idx, field_ty)) = - self.value_is_all_in_one_field(aggregate_ty, *variant_idx) - { - from = field_ty; - value = field_values[field_idx.as_usize()]; - was_updated = true; - if field_ty == to { - return Some(value); + // Aggregate-then-Transmute can just transmute the original field value, + // so long as the bytes of a value from only from a single field. + if let Transmute = kind + && let Value::Aggregate( + AggregateTy::Def(aggregate_did, aggregate_args), + variant_idx, + field_values, + ) = self.get(value) + && let aggregate_ty = + self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args) + && let Some((field_idx, field_ty)) = + self.value_is_all_in_one_field(aggregate_ty, *variant_idx) + { + from = field_ty; + value = field_values[field_idx.as_usize()]; + was_updated_this_iteration = true; + if field_ty == to { + return Some(value); + } } - } - // PtrToPtr-then-Transmute can just transmute the original, so long as the - // PtrToPtr didn't change metadata (and thus the size of the pointer) - if let Transmute = kind - && let Value::Cast { - kind: PtrToPtr, + // Various cast-then-cast cases can be simplified. + if let Value::Cast { + kind: inner_kind, value: inner_value, from: inner_from, to: inner_to, } = *self.get(value) - && self.pointers_have_same_metadata(inner_from, inner_to) - { - from = inner_from; - value = inner_value; - was_updated = true; - if inner_from == to { - return Some(inner_value); + { + let new_kind = match (inner_kind, *kind) { + // Even if there's a narrowing cast in here that's fine, because + // things like `*mut [i32] -> *mut i32 -> *const i32` and + // `*mut [i32] -> *const [i32] -> *const i32` can skip the middle in MIR. + (PtrToPtr, PtrToPtr) => Some(PtrToPtr), + // PtrToPtr-then-Transmute is fine so long as the pointer cast is identity: + // `*const T -> *mut T -> NonNull` is fine, but we need to check for narrowing + // to skip things like `*const [i32] -> *const i32 -> NonNull`. + (PtrToPtr, Transmute) + if self.pointers_have_same_metadata(inner_from, inner_to) => + { + Some(Transmute) + } + // Similarly, for Transmute-then-PtrToPtr. Note that we need to check different + // variables for their metadata, and thus this can't merge with the previous arm. + (Transmute, PtrToPtr) if self.pointers_have_same_metadata(from, to) => { + Some(Transmute) + } + // If would be legal to always do this, but we don't want to hide information + // from the backend that it'd otherwise be able to use for optimizations. + (Transmute, Transmute) + if !self.type_may_have_niche_of_interest_to_backend(inner_to) => + { + Some(Transmute) + } + _ => None, + }; + if let Some(new_kind) = new_kind { + *kind = new_kind; + from = inner_from; + value = inner_value; + was_updated_this_iteration = true; + if inner_from == to { + return Some(inner_value); + } + } } - } - // Transmute-then-PtrToPtr can just transmute the original, so long as the - // PtrToPtr won't change metadata (and thus the size of the pointer) - if let PtrToPtr = kind - && let Value::Cast { - kind: Transmute, - value: inner_value, - from: inner_from, - to: _inner_to, - } = *self.get(value) - && self.pointers_have_same_metadata(from, to) - { - *kind = Transmute; - from = inner_from; - value = inner_value; - was_updated = true; - if inner_from == to { - return Some(inner_value); + if was_updated_this_iteration { + was_ever_updated = true; + } else { + break; } } - if was_updated && let Some(op) = self.try_as_operand(value, location) { + if was_ever_updated && let Some(op) = self.try_as_operand(value, location) { *operand = op; } @@ -1492,6 +1494,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + /// Returns `false` if we know for sure that this type has no interesting niche, + /// and thus we can skip transmuting through it without worrying. + /// + /// The backend will emit `assume`s when transmuting between types with niches, + /// so we want to preserve `i32 -> char -> u32` so that that data is around, + /// but it's fine to skip whole-range-is-value steps like `A -> u32 -> B`. + fn type_may_have_niche_of_interest_to_backend(&self, ty: Ty<'tcx>) -> bool { + let Ok(layout) = self.ecx.layout_of(ty) else { + // If it's too generic or something, then assume it might be interesting later. + return true; + }; + + match layout.backend_repr { + BackendRepr::Uninhabited => true, + BackendRepr::Scalar(a) => !a.is_always_valid(&self.ecx), + BackendRepr::ScalarPair(a, b) => { + !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) + } + BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => false, + } + } + fn value_is_all_in_one_field( &self, ty: Ty<'tcx>, diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff index 2b234637f4d93..1f9291802472e 100644 --- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff @@ -17,15 +17,49 @@ let mut _14: u16; let _15: (); let mut _16: u16; - let mut _17: std::result::Result; + let mut _17: std::result::Result; + let mut _19: u16; + let _20: (); + let mut _21: u32; + let mut _22: std::option::Option; + let mut _24: u16; + let _25: (); + let mut _26: i16; + let mut _27: MyId; + let mut _29: u16; + let mut _30: u16; + let _31: (); + let mut _32: u32; + let mut _33: aggregate_struct_then_transmute::Pair; + let mut _35: u16; + let mut _36: u16; + let _37: (); + let mut _38: u16; + let mut _39: aggregate_struct_then_transmute::Pair; scope 1 { debug a => _2; let _7: TypedId; scope 2 { debug b => _7; - let _13: std::result::Result; + let _13: std::result::Result; scope 3 { debug c => _13; + let _18: std::option::Option; + scope 4 { + debug d => _18; + let _23: MyId; + scope 5 { + debug e => _23; + let _28: aggregate_struct_then_transmute::Pair; + scope 6 { + debug f => _28; + let _34: aggregate_struct_then_transmute::Pair; + scope 7 { + debug g => _34; + } + } + } + } } } } @@ -101,12 +135,105 @@ bb3: { StorageDead(_16); StorageDead(_15); +- StorageLive(_18); ++ nop; + StorageLive(_19); + _19 = copy _1; +- _18 = Option::::Some(move _19); ++ _18 = Option::::Some(copy _1); + StorageDead(_19); + StorageLive(_20); + StorageLive(_21); + StorageLive(_22); + _22 = copy _18; +- _21 = move _22 as u32 (Transmute); ++ _21 = copy _18 as u32 (Transmute); + StorageDead(_22); + _20 = opaque::(move _21) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_21); + StorageDead(_20); + StorageLive(_23); + StorageLive(_24); + _24 = copy _1; +- _23 = MyId(move _24); ++ _23 = copy _2; + StorageDead(_24); + StorageLive(_25); + StorageLive(_26); + StorageLive(_27); +- _27 = move _23; +- _26 = move _27 as i16 (Transmute); ++ _27 = copy _2; ++ _26 = copy _1 as i16 (Transmute); + StorageDead(_27); + _25 = opaque::(move _26) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_26); + StorageDead(_25); +- StorageLive(_28); ++ nop; + StorageLive(_29); + _29 = copy _1; + StorageLive(_30); + _30 = copy _1; +- _28 = Pair(move _29, move _30); ++ _28 = Pair(copy _1, copy _1); + StorageDead(_30); + StorageDead(_29); + StorageLive(_31); + StorageLive(_32); + StorageLive(_33); +- _33 = move _28; +- _32 = move _33 as u32 (Transmute); ++ _33 = copy _28; ++ _32 = copy _28 as u32 (Transmute); + StorageDead(_33); + _31 = opaque::(move _32) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_32); + StorageDead(_31); + StorageLive(_34); + StorageLive(_35); + _35 = copy _1; + StorageLive(_36); + _36 = copy _1; +- _34 = Pair(move _35, move _36); ++ _34 = copy _28; + StorageDead(_36); + StorageDead(_35); + StorageLive(_37); + StorageLive(_38); + StorageLive(_39); +- _39 = move _34; +- _38 = move _39 as u16 (Transmute); ++ _39 = copy _28; ++ _38 = copy _28 as u16 (Transmute); + StorageDead(_39); + _37 = opaque::(move _38) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_38); + StorageDead(_37); _0 = const (); + StorageDead(_34); +- StorageDead(_28); ++ nop; + StorageDead(_23); +- StorageDead(_18); - StorageDead(_13); - StorageDead(_7); - StorageDead(_2); + nop; + nop; ++ nop; + nop; return; } diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff index 2f36a3c393958..b6b6b1627b720 100644 --- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff @@ -17,15 +17,49 @@ let mut _14: u16; let _15: (); let mut _16: u16; - let mut _17: std::result::Result; + let mut _17: std::result::Result; + let mut _19: u16; + let _20: (); + let mut _21: u32; + let mut _22: std::option::Option; + let mut _24: u16; + let _25: (); + let mut _26: i16; + let mut _27: MyId; + let mut _29: u16; + let mut _30: u16; + let _31: (); + let mut _32: u32; + let mut _33: aggregate_struct_then_transmute::Pair; + let mut _35: u16; + let mut _36: u16; + let _37: (); + let mut _38: u16; + let mut _39: aggregate_struct_then_transmute::Pair; scope 1 { debug a => _2; let _7: TypedId; scope 2 { debug b => _7; - let _13: std::result::Result; + let _13: std::result::Result; scope 3 { debug c => _13; + let _18: std::option::Option; + scope 4 { + debug d => _18; + let _23: MyId; + scope 5 { + debug e => _23; + let _28: aggregate_struct_then_transmute::Pair; + scope 6 { + debug f => _28; + let _34: aggregate_struct_then_transmute::Pair; + scope 7 { + debug g => _34; + } + } + } + } } } } @@ -101,12 +135,105 @@ bb3: { StorageDead(_16); StorageDead(_15); +- StorageLive(_18); ++ nop; + StorageLive(_19); + _19 = copy _1; +- _18 = Option::::Some(move _19); ++ _18 = Option::::Some(copy _1); + StorageDead(_19); + StorageLive(_20); + StorageLive(_21); + StorageLive(_22); + _22 = copy _18; +- _21 = move _22 as u32 (Transmute); ++ _21 = copy _18 as u32 (Transmute); + StorageDead(_22); + _20 = opaque::(move _21) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_21); + StorageDead(_20); + StorageLive(_23); + StorageLive(_24); + _24 = copy _1; +- _23 = MyId(move _24); ++ _23 = copy _2; + StorageDead(_24); + StorageLive(_25); + StorageLive(_26); + StorageLive(_27); +- _27 = move _23; +- _26 = move _27 as i16 (Transmute); ++ _27 = copy _2; ++ _26 = copy _1 as i16 (Transmute); + StorageDead(_27); + _25 = opaque::(move _26) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_26); + StorageDead(_25); +- StorageLive(_28); ++ nop; + StorageLive(_29); + _29 = copy _1; + StorageLive(_30); + _30 = copy _1; +- _28 = Pair(move _29, move _30); ++ _28 = Pair(copy _1, copy _1); + StorageDead(_30); + StorageDead(_29); + StorageLive(_31); + StorageLive(_32); + StorageLive(_33); +- _33 = move _28; +- _32 = move _33 as u32 (Transmute); ++ _33 = copy _28; ++ _32 = copy _28 as u32 (Transmute); + StorageDead(_33); + _31 = opaque::(move _32) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_32); + StorageDead(_31); + StorageLive(_34); + StorageLive(_35); + _35 = copy _1; + StorageLive(_36); + _36 = copy _1; +- _34 = Pair(move _35, move _36); ++ _34 = copy _28; + StorageDead(_36); + StorageDead(_35); + StorageLive(_37); + StorageLive(_38); + StorageLive(_39); +- _39 = move _34; +- _38 = move _39 as u16 (Transmute); ++ _39 = copy _28; ++ _38 = copy _28 as u16 (Transmute); + StorageDead(_39); + _37 = opaque::(move _38) -> [return: bb7, unwind continue]; + } + + bb7: { + StorageDead(_38); + StorageDead(_37); _0 = const (); + StorageDead(_34); +- StorageDead(_28); ++ nop; + StorageDead(_23); +- StorageDead(_18); - StorageDead(_13); - StorageDead(_7); - StorageDead(_2); + nop; + nop; ++ nop; + nop; return; } diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 3f9f0a0be37ce..17357fed5a59e 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -946,7 +946,42 @@ unsafe fn aggregate_struct_then_transmute(id: u16) { let c = Err::(id); opaque(std::intrinsics::transmute::<_, u16>(c)); - enum Never {} + // CHECK: [[TEMP1:_[0-9]+]] = Option::::Some(copy _1); + // CHECK: [[TEMP2:_[0-9]+]] = copy [[TEMP1]] as u32 (Transmute); + // CHECK: opaque::(move [[TEMP2]]) + let d = Some(id); + opaque(std::intrinsics::transmute::<_, u32>(d)); + + // Still need the transmute, but the aggregate can be skipped + // CHECK: [[TEMP:_[0-9]+]] = copy _1 as i16 (Transmute); + // CHECK: opaque::(move [[TEMP]]) + let e = MyId(id); + opaque(std::intrinsics::transmute::<_, i16>(e)); + + // CHECK: [[PAIR:_[0-9]+]] = Pair(copy _1, copy _1); + // CHECK: [[TEMP:_[0-9]+]] = copy [[PAIR]] as u32 (Transmute); + // CHECK: opaque::(move [[TEMP]]) + struct Pair(u16, u16); + let f = Pair(id, id); + opaque(std::intrinsics::transmute::<_, u32>(f)); + + // CHECK: [[TEMP:_[0-9]+]] = copy [[PAIR]] as u16 (Transmute); + // CHECK: opaque::(move [[TEMP]]) + let g = Pair(id, id); + opaque(std::intrinsics::transmute_unchecked::<_, u16>(g)); +} + +unsafe fn transmute_then_transmute_again(a: u32, c: char) { + // CHECK: [[TEMP1:_[0-9]+]] = copy _1 as char (Transmute); + // CHECK: [[TEMP2:_[0-9]+]] = copy [[TEMP1]] as i32 (Transmute); + // CHECK: opaque::(move [[TEMP2]]) + let x = std::intrinsics::transmute::(a); + opaque(std::intrinsics::transmute::(x)); + + // CHECK: [[TEMP:_[0-9]+]] = copy _2 as i32 (Transmute); + // CHECK: opaque::(move [[TEMP]]) + let x = std::intrinsics::transmute::(c); + opaque(std::intrinsics::transmute::(x)); } // Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast. @@ -1050,6 +1085,8 @@ struct MyId(u16); #[repr(transparent)] struct TypedId(u16, PhantomData); +enum Never {} + // EMIT_MIR gvn.subexpression_elimination.GVN.diff // EMIT_MIR gvn.wrap_unwrap.GVN.diff // EMIT_MIR gvn.repeated_index.GVN.diff @@ -1083,6 +1120,7 @@ struct TypedId(u16, PhantomData); // EMIT_MIR gvn.generic_cast_metadata.GVN.diff // EMIT_MIR gvn.cast_pointer_eq.GVN.diff // EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff +// EMIT_MIR gvn.transmute_then_transmute_again.GVN.diff // EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff // EMIT_MIR gvn.transmute_then_cast_pointer.GVN.diff // EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff diff --git a/tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-abort.diff b/tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-abort.diff new file mode 100644 index 0000000000000..962fecd2586eb --- /dev/null +++ b/tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-abort.diff @@ -0,0 +1,74 @@ +- // MIR for `transmute_then_transmute_again` before GVN ++ // MIR for `transmute_then_transmute_again` after GVN + + fn transmute_then_transmute_again(_1: u32, _2: char) -> () { + debug a => _1; + debug c => _2; + let mut _0: (); + let _3: char; + let mut _4: u32; + let _5: (); + let mut _6: i32; + let mut _7: char; + let mut _9: char; + let _10: (); + let mut _11: i32; + let mut _12: u32; + scope 1 { + debug x => _3; + let _8: u32; + scope 2 { + debug x => _8; + } + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as char (Transmute); ++ _3 = copy _1 as char (Transmute); + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _3; +- _6 = move _7 as i32 (Transmute); ++ _6 = copy _3 as i32 (Transmute); + StorageDead(_7); + _5 = opaque::(move _6) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_6); + StorageDead(_5); +- StorageLive(_8); ++ nop; + StorageLive(_9); + _9 = copy _2; +- _8 = move _9 as u32 (Transmute); ++ _8 = copy _2 as u32 (Transmute); + StorageDead(_9); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); + _12 = copy _8; +- _11 = move _12 as i32 (Transmute); ++ _11 = copy _2 as i32 (Transmute); + StorageDead(_12); + _10 = opaque::(move _11) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_11); + StorageDead(_10); + _0 = const (); +- StorageDead(_8); +- StorageDead(_3); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-unwind.diff b/tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..e32397c1aed07 --- /dev/null +++ b/tests/mir-opt/gvn.transmute_then_transmute_again.GVN.panic-unwind.diff @@ -0,0 +1,74 @@ +- // MIR for `transmute_then_transmute_again` before GVN ++ // MIR for `transmute_then_transmute_again` after GVN + + fn transmute_then_transmute_again(_1: u32, _2: char) -> () { + debug a => _1; + debug c => _2; + let mut _0: (); + let _3: char; + let mut _4: u32; + let _5: (); + let mut _6: i32; + let mut _7: char; + let mut _9: char; + let _10: (); + let mut _11: i32; + let mut _12: u32; + scope 1 { + debug x => _3; + let _8: u32; + scope 2 { + debug x => _8; + } + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = copy _1; +- _3 = move _4 as char (Transmute); ++ _3 = copy _1 as char (Transmute); + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _3; +- _6 = move _7 as i32 (Transmute); ++ _6 = copy _3 as i32 (Transmute); + StorageDead(_7); + _5 = opaque::(move _6) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_6); + StorageDead(_5); +- StorageLive(_8); ++ nop; + StorageLive(_9); + _9 = copy _2; +- _8 = move _9 as u32 (Transmute); ++ _8 = copy _2 as u32 (Transmute); + StorageDead(_9); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); + _12 = copy _8; +- _11 = move _12 as i32 (Transmute); ++ _11 = copy _2 as i32 (Transmute); + StorageDead(_12); + _10 = opaque::(move _11) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_11); + StorageDead(_10); + _0 = const (); +- StorageDead(_8); +- StorageDead(_3); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 9494b8a2addb1..a2ef53e0e1308 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -90,11 +90,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageLive(_11); StorageLive(_3); StorageLive(_6); - StorageLive(_5); + StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); + StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull:: { pointer: copy _5 }; + _6 = NonNull:: { pointer: move _5 }; + StorageDead(_5); StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -121,7 +123,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); - StorageDead(_5); + StorageDead(_4); StorageDead(_6); StorageDead(_3); _12 = Enumerate::> { iter: copy _11, count: const 0_usize }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index c9b9798bf33f3..c1b846e662bc2 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -65,11 +65,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageLive(_11); StorageLive(_3); StorageLive(_6); - StorageLive(_5); + StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); + StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull:: { pointer: copy _5 }; + _6 = NonNull:: { pointer: move _5 }; + StorageDead(_5); StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -96,7 +98,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); - StorageDead(_5); + StorageDead(_4); StorageDead(_6); StorageDead(_3); _12 = Enumerate::> { iter: copy _11, count: const 0_usize }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index ac6fe0ac547ab..8cebf2c6bace6 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -57,11 +57,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb0: { StorageLive(_3); StorageLive(_6); - StorageLive(_5); + StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); + StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull:: { pointer: copy _5 }; + _6 = NonNull:: { pointer: move _5 }; + StorageDead(_5); StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -88,7 +90,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); - StorageDead(_5); + StorageDead(_4); StorageDead(_6); StorageDead(_3); StorageLive(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index bc2403fc544a8..e7e39240fed58 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -57,11 +57,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb0: { StorageLive(_3); StorageLive(_6); - StorageLive(_5); + StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); + StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull:: { pointer: copy _5 }; + _6 = NonNull:: { pointer: move _5 }; + StorageDead(_5); StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -88,7 +90,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); - StorageDead(_5); + StorageDead(_4); StorageDead(_6); StorageDead(_3); StorageLive(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 0eac3342ff73d..58f95d0a43231 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -65,11 +65,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_11); StorageLive(_3); StorageLive(_6); - StorageLive(_5); + StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); + StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull:: { pointer: copy _5 }; + _6 = NonNull:: { pointer: move _5 }; + StorageDead(_5); StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -96,7 +98,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); - StorageDead(_5); + StorageDead(_4); StorageDead(_6); StorageDead(_3); _12 = Rev::> { iter: copy _11 }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index 376dc7163821a..e7ddacf314457 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -65,11 +65,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_11); StorageLive(_3); StorageLive(_6); - StorageLive(_5); + StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); + StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull:: { pointer: copy _5 }; + _6 = NonNull:: { pointer: move _5 }; + StorageDead(_5); StorageLive(_9); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -96,7 +98,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); - StorageDead(_5); + StorageDead(_4); StorageDead(_6); StorageDead(_3); _12 = Rev::> { iter: copy _11 }; From b421a563644dafdb8a5a9c48fe21c4a449da18fa Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 5 Jan 2025 23:27:24 -0800 Subject: [PATCH 131/189] Make the aggregate-then-transmute handling more general --- compiler/rustc_mir_transform/src/gvn.rs | 22 +- ...struct_then_transmute.GVN.panic-abort.diff | 393 +++++++++++------- ...truct_then_transmute.GVN.panic-unwind.diff | 393 +++++++++++------- tests/mir-opt/gvn.rs | 14 +- 4 files changed, 514 insertions(+), 308 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 7c600fc1ceb2a..71bec38c405d8 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1370,12 +1370,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { loop { let mut was_updated_this_iteration = false; - // Transmuting `*const T` <=> `*mut T` is just a pointer cast, - // which we might be able to merge with other ones later. + // Transmuting between raw pointers is just a pointer cast so long as + // they have the same metadata type (like `*const i32` <=> `*mut u64` + // or `*mut [i32]` <=> `*const [u64]`), including the common special + // case of `*const T` <=> `*mut T`. if let Transmute = kind - && let ty::RawPtr(from_pointee, _) = from.kind() - && let ty::RawPtr(to_pointee, _) = to.kind() - && from_pointee == to_pointee + && from.is_unsafe_ptr() + && to.is_unsafe_ptr() + && self.pointers_have_same_metadata(from, to) { *kind = PtrToPtr; was_updated_this_iteration = true; @@ -1400,15 +1402,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Aggregate-then-Transmute can just transmute the original field value, // so long as the bytes of a value from only from a single field. if let Transmute = kind - && let Value::Aggregate( - AggregateTy::Def(aggregate_did, aggregate_args), - variant_idx, - field_values, - ) = self.get(value) - && let aggregate_ty = - self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args) + && let Value::Aggregate(_aggregate_ty, variant_idx, field_values) = self.get(value) && let Some((field_idx, field_ty)) = - self.value_is_all_in_one_field(aggregate_ty, *variant_idx) + self.value_is_all_in_one_field(from, *variant_idx) { from = field_ty; value = field_values[field_idx.as_usize()]; diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff index 1f9291802472e..5ae575f300afb 100644 --- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff @@ -1,61 +1,87 @@ - // MIR for `aggregate_struct_then_transmute` before GVN + // MIR for `aggregate_struct_then_transmute` after GVN - fn aggregate_struct_then_transmute(_1: u16) -> () { + fn aggregate_struct_then_transmute(_1: u16, _2: *const u8) -> () { debug id => _1; + debug thin => _2; let mut _0: (); - let _2: MyId; - let mut _3: u16; - let _4: (); - let mut _5: u16; - let mut _6: MyId; - let mut _8: u16; - let mut _9: std::marker::PhantomData; - let _10: (); - let mut _11: u16; - let mut _12: TypedId; - let mut _14: u16; - let _15: (); - let mut _16: u16; - let mut _17: std::result::Result; - let mut _19: u16; - let _20: (); - let mut _21: u32; - let mut _22: std::option::Option; - let mut _24: u16; - let _25: (); - let mut _26: i16; - let mut _27: MyId; - let mut _29: u16; + let _3: MyId; + let mut _4: u16; + let _5: (); + let mut _6: u16; + let mut _7: MyId; + let mut _9: u16; + let mut _10: std::marker::PhantomData; + let _11: (); + let mut _12: u16; + let mut _13: TypedId; + let mut _15: u16; + let _16: (); + let mut _17: u16; + let mut _18: std::result::Result; + let mut _20: u16; + let _21: (); + let mut _22: u32; + let mut _23: std::option::Option; + let mut _25: u16; + let _26: (); + let mut _27: i16; + let mut _28: MyId; let mut _30: u16; - let _31: (); - let mut _32: u32; - let mut _33: aggregate_struct_then_transmute::Pair; - let mut _35: u16; + let mut _31: u16; + let _32: (); + let mut _33: u32; + let mut _34: aggregate_struct_then_transmute::Pair; let mut _36: u16; - let _37: (); - let mut _38: u16; - let mut _39: aggregate_struct_then_transmute::Pair; + let mut _37: u16; + let _38: (); + let mut _39: u16; + let mut _40: aggregate_struct_then_transmute::Pair; + let mut _42: u16; + let _43: (); + let mut _44: u16; + let mut _45: (u16,); + let mut _47: u16; + let _48: (); + let mut _49: u16; + let mut _50: [u16; 1]; + let mut _52: *const u8; + let mut _53: (); + let _54: (); + let mut _55: *const u8; + let mut _56: *const i32; scope 1 { - debug a => _2; - let _7: TypedId; + debug a => _3; + let _8: TypedId; scope 2 { - debug b => _7; - let _13: std::result::Result; + debug b => _8; + let _14: std::result::Result; scope 3 { - debug c => _13; - let _18: std::option::Option; + debug c => _14; + let _19: std::option::Option; scope 4 { - debug d => _18; - let _23: MyId; + debug d => _19; + let _24: MyId; scope 5 { - debug e => _23; - let _28: aggregate_struct_then_transmute::Pair; + debug e => _24; + let _29: aggregate_struct_then_transmute::Pair; scope 6 { - debug f => _28; - let _34: aggregate_struct_then_transmute::Pair; + debug f => _29; + let _35: aggregate_struct_then_transmute::Pair; scope 7 { - debug g => _34; + debug g => _35; + let _41: (u16,); + scope 8 { + debug h => _41; + let _46: [u16; 1]; + scope 9 { + debug i => _46; + let _51: *const i32; + scope 10 { + debug j => _51; + } + } + } } } } @@ -65,172 +91,245 @@ } bb0: { -- StorageLive(_2); +- StorageLive(_3); + nop; - StorageLive(_3); - _3 = copy _1; -- _2 = MyId(move _3); -+ _2 = MyId(copy _1); - StorageDead(_3); StorageLive(_4); + _4 = copy _1; +- _3 = MyId(move _4); ++ _3 = MyId(copy _1); + StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = move _2; -- _5 = move _6 as u16 (Transmute); -+ _6 = copy _2; -+ _5 = copy _1; - StorageDead(_6); -- _4 = opaque::(move _5) -> [return: bb1, unwind unreachable]; -+ _4 = opaque::(copy _1) -> [return: bb1, unwind unreachable]; + StorageLive(_7); +- _7 = move _3; +- _6 = move _7 as u16 (Transmute); ++ _7 = copy _3; ++ _6 = copy _1; + StorageDead(_7); +- _5 = opaque::(move _6) -> [return: bb1, unwind unreachable]; ++ _5 = opaque::(copy _1) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_6); StorageDead(_5); - StorageDead(_4); -- StorageLive(_7); +- StorageLive(_8); + nop; - StorageLive(_8); - _8 = copy _1; StorageLive(_9); -- _9 = PhantomData::; -- _7 = TypedId::(move _8, move _9); -+ _9 = const PhantomData::; -+ _7 = TypedId::(copy _1, const PhantomData::); - StorageDead(_9); - StorageDead(_8); + _9 = copy _1; StorageLive(_10); +- _10 = PhantomData::; +- _8 = TypedId::(move _9, move _10); ++ _10 = const PhantomData::; ++ _8 = TypedId::(copy _1, const PhantomData::); + StorageDead(_10); + StorageDead(_9); StorageLive(_11); StorageLive(_12); -- _12 = move _7; -- _11 = move _12 as u16 (Transmute); -+ _12 = copy _7; -+ _11 = copy _1; - StorageDead(_12); -- _10 = opaque::(move _11) -> [return: bb2, unwind unreachable]; -+ _10 = opaque::(copy _1) -> [return: bb2, unwind unreachable]; + StorageLive(_13); +- _13 = move _8; +- _12 = move _13 as u16 (Transmute); ++ _13 = copy _8; ++ _12 = copy _1; + StorageDead(_13); +- _11 = opaque::(move _12) -> [return: bb2, unwind unreachable]; ++ _11 = opaque::(copy _1) -> [return: bb2, unwind unreachable]; } bb2: { + StorageDead(_12); StorageDead(_11); - StorageDead(_10); -- StorageLive(_13); +- StorageLive(_14); + nop; - StorageLive(_14); - _14 = copy _1; -- _13 = Result::::Err(move _14); -+ _13 = Result::::Err(copy _1); - StorageDead(_14); StorageLive(_15); + _15 = copy _1; +- _14 = Result::::Err(move _15); ++ _14 = Result::::Err(copy _1); + StorageDead(_15); StorageLive(_16); StorageLive(_17); -- _17 = move _13; -- _16 = move _17 as u16 (Transmute); -+ _17 = copy _13; -+ _16 = copy _1; - StorageDead(_17); -- _15 = opaque::(move _16) -> [return: bb3, unwind unreachable]; -+ _15 = opaque::(copy _1) -> [return: bb3, unwind unreachable]; + StorageLive(_18); +- _18 = move _14; +- _17 = move _18 as u16 (Transmute); ++ _18 = copy _14; ++ _17 = copy _1; + StorageDead(_18); +- _16 = opaque::(move _17) -> [return: bb3, unwind unreachable]; ++ _16 = opaque::(copy _1) -> [return: bb3, unwind unreachable]; } bb3: { + StorageDead(_17); StorageDead(_16); - StorageDead(_15); -- StorageLive(_18); +- StorageLive(_19); + nop; - StorageLive(_19); - _19 = copy _1; -- _18 = Option::::Some(move _19); -+ _18 = Option::::Some(copy _1); - StorageDead(_19); StorageLive(_20); + _20 = copy _1; +- _19 = Option::::Some(move _20); ++ _19 = Option::::Some(copy _1); + StorageDead(_20); StorageLive(_21); StorageLive(_22); - _22 = copy _18; -- _21 = move _22 as u32 (Transmute); -+ _21 = copy _18 as u32 (Transmute); - StorageDead(_22); - _20 = opaque::(move _21) -> [return: bb4, unwind unreachable]; + StorageLive(_23); + _23 = copy _19; +- _22 = move _23 as u32 (Transmute); ++ _22 = copy _19 as u32 (Transmute); + StorageDead(_23); + _21 = opaque::(move _22) -> [return: bb4, unwind unreachable]; } bb4: { + StorageDead(_22); StorageDead(_21); - StorageDead(_20); - StorageLive(_23); StorageLive(_24); - _24 = copy _1; -- _23 = MyId(move _24); -+ _23 = copy _2; - StorageDead(_24); StorageLive(_25); + _25 = copy _1; +- _24 = MyId(move _25); ++ _24 = copy _3; + StorageDead(_25); StorageLive(_26); StorageLive(_27); -- _27 = move _23; -- _26 = move _27 as i16 (Transmute); -+ _27 = copy _2; -+ _26 = copy _1 as i16 (Transmute); - StorageDead(_27); - _25 = opaque::(move _26) -> [return: bb5, unwind unreachable]; + StorageLive(_28); +- _28 = move _24; +- _27 = move _28 as i16 (Transmute); ++ _28 = copy _3; ++ _27 = copy _1 as i16 (Transmute); + StorageDead(_28); + _26 = opaque::(move _27) -> [return: bb5, unwind unreachable]; } bb5: { + StorageDead(_27); StorageDead(_26); - StorageDead(_25); -- StorageLive(_28); +- StorageLive(_29); + nop; - StorageLive(_29); - _29 = copy _1; StorageLive(_30); _30 = copy _1; -- _28 = Pair(move _29, move _30); -+ _28 = Pair(copy _1, copy _1); - StorageDead(_30); - StorageDead(_29); StorageLive(_31); + _31 = copy _1; +- _29 = Pair(move _30, move _31); ++ _29 = Pair(copy _1, copy _1); + StorageDead(_31); + StorageDead(_30); StorageLive(_32); StorageLive(_33); -- _33 = move _28; -- _32 = move _33 as u32 (Transmute); -+ _33 = copy _28; -+ _32 = copy _28 as u32 (Transmute); - StorageDead(_33); - _31 = opaque::(move _32) -> [return: bb6, unwind unreachable]; + StorageLive(_34); +- _34 = move _29; +- _33 = move _34 as u32 (Transmute); ++ _34 = copy _29; ++ _33 = copy _29 as u32 (Transmute); + StorageDead(_34); + _32 = opaque::(move _33) -> [return: bb6, unwind unreachable]; } bb6: { + StorageDead(_33); StorageDead(_32); - StorageDead(_31); - StorageLive(_34); StorageLive(_35); - _35 = copy _1; StorageLive(_36); _36 = copy _1; -- _34 = Pair(move _35, move _36); -+ _34 = copy _28; - StorageDead(_36); - StorageDead(_35); StorageLive(_37); + _37 = copy _1; +- _35 = Pair(move _36, move _37); ++ _35 = copy _29; + StorageDead(_37); + StorageDead(_36); StorageLive(_38); StorageLive(_39); -- _39 = move _34; -- _38 = move _39 as u16 (Transmute); -+ _39 = copy _28; -+ _38 = copy _28 as u16 (Transmute); - StorageDead(_39); - _37 = opaque::(move _38) -> [return: bb7, unwind unreachable]; + StorageLive(_40); +- _40 = move _35; +- _39 = move _40 as u16 (Transmute); ++ _40 = copy _29; ++ _39 = copy _29 as u16 (Transmute); + StorageDead(_40); + _38 = opaque::(move _39) -> [return: bb7, unwind unreachable]; } bb7: { + StorageDead(_39); StorageDead(_38); - StorageDead(_37); +- StorageLive(_41); ++ nop; + StorageLive(_42); + _42 = copy _1; +- _41 = (move _42,); ++ _41 = (copy _1,); + StorageDead(_42); + StorageLive(_43); + StorageLive(_44); + StorageLive(_45); + _45 = copy _41; +- _44 = move _45 as u16 (Transmute); ++ _44 = copy _1; + StorageDead(_45); +- _43 = opaque::(move _44) -> [return: bb8, unwind unreachable]; ++ _43 = opaque::(copy _1) -> [return: bb8, unwind unreachable]; + } + + bb8: { + StorageDead(_44); + StorageDead(_43); +- StorageLive(_46); ++ nop; + StorageLive(_47); + _47 = copy _1; +- _46 = [move _47]; ++ _46 = [copy _1]; + StorageDead(_47); + StorageLive(_48); + StorageLive(_49); + StorageLive(_50); + _50 = copy _46; +- _49 = move _50 as u16 (Transmute); ++ _49 = copy _1; + StorageDead(_50); +- _48 = opaque::(move _49) -> [return: bb9, unwind unreachable]; ++ _48 = opaque::(copy _1) -> [return: bb9, unwind unreachable]; + } + + bb9: { + StorageDead(_49); + StorageDead(_48); +- StorageLive(_51); ++ nop; + StorageLive(_52); + _52 = copy _2; + StorageLive(_53); +- _53 = (); +- _51 = *const i32 from (move _52, move _53); ++ _53 = const (); ++ _51 = *const i32 from (copy _2, const ()); + StorageDead(_53); + StorageDead(_52); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); + _56 = copy _51; +- _55 = move _56 as *const u8 (Transmute); ++ _55 = copy _2; + StorageDead(_56); +- _54 = opaque::<*const u8>(move _55) -> [return: bb10, unwind unreachable]; ++ _54 = opaque::<*const u8>(copy _2) -> [return: bb10, unwind unreachable]; + } + + bb10: { + StorageDead(_55); + StorageDead(_54); _0 = const (); - StorageDead(_34); -- StorageDead(_28); +- StorageDead(_51); +- StorageDead(_46); +- StorageDead(_41); + nop; - StorageDead(_23); -- StorageDead(_18); -- StorageDead(_13); -- StorageDead(_7); -- StorageDead(_2); ++ nop; ++ nop; + StorageDead(_35); +- StorageDead(_29); ++ nop; + StorageDead(_24); +- StorageDead(_19); +- StorageDead(_14); +- StorageDead(_8); +- StorageDead(_3); + nop; + nop; + nop; diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff index b6b6b1627b720..3119a93fb8912 100644 --- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff @@ -1,61 +1,87 @@ - // MIR for `aggregate_struct_then_transmute` before GVN + // MIR for `aggregate_struct_then_transmute` after GVN - fn aggregate_struct_then_transmute(_1: u16) -> () { + fn aggregate_struct_then_transmute(_1: u16, _2: *const u8) -> () { debug id => _1; + debug thin => _2; let mut _0: (); - let _2: MyId; - let mut _3: u16; - let _4: (); - let mut _5: u16; - let mut _6: MyId; - let mut _8: u16; - let mut _9: std::marker::PhantomData; - let _10: (); - let mut _11: u16; - let mut _12: TypedId; - let mut _14: u16; - let _15: (); - let mut _16: u16; - let mut _17: std::result::Result; - let mut _19: u16; - let _20: (); - let mut _21: u32; - let mut _22: std::option::Option; - let mut _24: u16; - let _25: (); - let mut _26: i16; - let mut _27: MyId; - let mut _29: u16; + let _3: MyId; + let mut _4: u16; + let _5: (); + let mut _6: u16; + let mut _7: MyId; + let mut _9: u16; + let mut _10: std::marker::PhantomData; + let _11: (); + let mut _12: u16; + let mut _13: TypedId; + let mut _15: u16; + let _16: (); + let mut _17: u16; + let mut _18: std::result::Result; + let mut _20: u16; + let _21: (); + let mut _22: u32; + let mut _23: std::option::Option; + let mut _25: u16; + let _26: (); + let mut _27: i16; + let mut _28: MyId; let mut _30: u16; - let _31: (); - let mut _32: u32; - let mut _33: aggregate_struct_then_transmute::Pair; - let mut _35: u16; + let mut _31: u16; + let _32: (); + let mut _33: u32; + let mut _34: aggregate_struct_then_transmute::Pair; let mut _36: u16; - let _37: (); - let mut _38: u16; - let mut _39: aggregate_struct_then_transmute::Pair; + let mut _37: u16; + let _38: (); + let mut _39: u16; + let mut _40: aggregate_struct_then_transmute::Pair; + let mut _42: u16; + let _43: (); + let mut _44: u16; + let mut _45: (u16,); + let mut _47: u16; + let _48: (); + let mut _49: u16; + let mut _50: [u16; 1]; + let mut _52: *const u8; + let mut _53: (); + let _54: (); + let mut _55: *const u8; + let mut _56: *const i32; scope 1 { - debug a => _2; - let _7: TypedId; + debug a => _3; + let _8: TypedId; scope 2 { - debug b => _7; - let _13: std::result::Result; + debug b => _8; + let _14: std::result::Result; scope 3 { - debug c => _13; - let _18: std::option::Option; + debug c => _14; + let _19: std::option::Option; scope 4 { - debug d => _18; - let _23: MyId; + debug d => _19; + let _24: MyId; scope 5 { - debug e => _23; - let _28: aggregate_struct_then_transmute::Pair; + debug e => _24; + let _29: aggregate_struct_then_transmute::Pair; scope 6 { - debug f => _28; - let _34: aggregate_struct_then_transmute::Pair; + debug f => _29; + let _35: aggregate_struct_then_transmute::Pair; scope 7 { - debug g => _34; + debug g => _35; + let _41: (u16,); + scope 8 { + debug h => _41; + let _46: [u16; 1]; + scope 9 { + debug i => _46; + let _51: *const i32; + scope 10 { + debug j => _51; + } + } + } } } } @@ -65,172 +91,245 @@ } bb0: { -- StorageLive(_2); +- StorageLive(_3); + nop; - StorageLive(_3); - _3 = copy _1; -- _2 = MyId(move _3); -+ _2 = MyId(copy _1); - StorageDead(_3); StorageLive(_4); + _4 = copy _1; +- _3 = MyId(move _4); ++ _3 = MyId(copy _1); + StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = move _2; -- _5 = move _6 as u16 (Transmute); -+ _6 = copy _2; -+ _5 = copy _1; - StorageDead(_6); -- _4 = opaque::(move _5) -> [return: bb1, unwind continue]; -+ _4 = opaque::(copy _1) -> [return: bb1, unwind continue]; + StorageLive(_7); +- _7 = move _3; +- _6 = move _7 as u16 (Transmute); ++ _7 = copy _3; ++ _6 = copy _1; + StorageDead(_7); +- _5 = opaque::(move _6) -> [return: bb1, unwind continue]; ++ _5 = opaque::(copy _1) -> [return: bb1, unwind continue]; } bb1: { + StorageDead(_6); StorageDead(_5); - StorageDead(_4); -- StorageLive(_7); +- StorageLive(_8); + nop; - StorageLive(_8); - _8 = copy _1; StorageLive(_9); -- _9 = PhantomData::; -- _7 = TypedId::(move _8, move _9); -+ _9 = const PhantomData::; -+ _7 = TypedId::(copy _1, const PhantomData::); - StorageDead(_9); - StorageDead(_8); + _9 = copy _1; StorageLive(_10); +- _10 = PhantomData::; +- _8 = TypedId::(move _9, move _10); ++ _10 = const PhantomData::; ++ _8 = TypedId::(copy _1, const PhantomData::); + StorageDead(_10); + StorageDead(_9); StorageLive(_11); StorageLive(_12); -- _12 = move _7; -- _11 = move _12 as u16 (Transmute); -+ _12 = copy _7; -+ _11 = copy _1; - StorageDead(_12); -- _10 = opaque::(move _11) -> [return: bb2, unwind continue]; -+ _10 = opaque::(copy _1) -> [return: bb2, unwind continue]; + StorageLive(_13); +- _13 = move _8; +- _12 = move _13 as u16 (Transmute); ++ _13 = copy _8; ++ _12 = copy _1; + StorageDead(_13); +- _11 = opaque::(move _12) -> [return: bb2, unwind continue]; ++ _11 = opaque::(copy _1) -> [return: bb2, unwind continue]; } bb2: { + StorageDead(_12); StorageDead(_11); - StorageDead(_10); -- StorageLive(_13); +- StorageLive(_14); + nop; - StorageLive(_14); - _14 = copy _1; -- _13 = Result::::Err(move _14); -+ _13 = Result::::Err(copy _1); - StorageDead(_14); StorageLive(_15); + _15 = copy _1; +- _14 = Result::::Err(move _15); ++ _14 = Result::::Err(copy _1); + StorageDead(_15); StorageLive(_16); StorageLive(_17); -- _17 = move _13; -- _16 = move _17 as u16 (Transmute); -+ _17 = copy _13; -+ _16 = copy _1; - StorageDead(_17); -- _15 = opaque::(move _16) -> [return: bb3, unwind continue]; -+ _15 = opaque::(copy _1) -> [return: bb3, unwind continue]; + StorageLive(_18); +- _18 = move _14; +- _17 = move _18 as u16 (Transmute); ++ _18 = copy _14; ++ _17 = copy _1; + StorageDead(_18); +- _16 = opaque::(move _17) -> [return: bb3, unwind continue]; ++ _16 = opaque::(copy _1) -> [return: bb3, unwind continue]; } bb3: { + StorageDead(_17); StorageDead(_16); - StorageDead(_15); -- StorageLive(_18); +- StorageLive(_19); + nop; - StorageLive(_19); - _19 = copy _1; -- _18 = Option::::Some(move _19); -+ _18 = Option::::Some(copy _1); - StorageDead(_19); StorageLive(_20); + _20 = copy _1; +- _19 = Option::::Some(move _20); ++ _19 = Option::::Some(copy _1); + StorageDead(_20); StorageLive(_21); StorageLive(_22); - _22 = copy _18; -- _21 = move _22 as u32 (Transmute); -+ _21 = copy _18 as u32 (Transmute); - StorageDead(_22); - _20 = opaque::(move _21) -> [return: bb4, unwind continue]; + StorageLive(_23); + _23 = copy _19; +- _22 = move _23 as u32 (Transmute); ++ _22 = copy _19 as u32 (Transmute); + StorageDead(_23); + _21 = opaque::(move _22) -> [return: bb4, unwind continue]; } bb4: { + StorageDead(_22); StorageDead(_21); - StorageDead(_20); - StorageLive(_23); StorageLive(_24); - _24 = copy _1; -- _23 = MyId(move _24); -+ _23 = copy _2; - StorageDead(_24); StorageLive(_25); + _25 = copy _1; +- _24 = MyId(move _25); ++ _24 = copy _3; + StorageDead(_25); StorageLive(_26); StorageLive(_27); -- _27 = move _23; -- _26 = move _27 as i16 (Transmute); -+ _27 = copy _2; -+ _26 = copy _1 as i16 (Transmute); - StorageDead(_27); - _25 = opaque::(move _26) -> [return: bb5, unwind continue]; + StorageLive(_28); +- _28 = move _24; +- _27 = move _28 as i16 (Transmute); ++ _28 = copy _3; ++ _27 = copy _1 as i16 (Transmute); + StorageDead(_28); + _26 = opaque::(move _27) -> [return: bb5, unwind continue]; } bb5: { + StorageDead(_27); StorageDead(_26); - StorageDead(_25); -- StorageLive(_28); +- StorageLive(_29); + nop; - StorageLive(_29); - _29 = copy _1; StorageLive(_30); _30 = copy _1; -- _28 = Pair(move _29, move _30); -+ _28 = Pair(copy _1, copy _1); - StorageDead(_30); - StorageDead(_29); StorageLive(_31); + _31 = copy _1; +- _29 = Pair(move _30, move _31); ++ _29 = Pair(copy _1, copy _1); + StorageDead(_31); + StorageDead(_30); StorageLive(_32); StorageLive(_33); -- _33 = move _28; -- _32 = move _33 as u32 (Transmute); -+ _33 = copy _28; -+ _32 = copy _28 as u32 (Transmute); - StorageDead(_33); - _31 = opaque::(move _32) -> [return: bb6, unwind continue]; + StorageLive(_34); +- _34 = move _29; +- _33 = move _34 as u32 (Transmute); ++ _34 = copy _29; ++ _33 = copy _29 as u32 (Transmute); + StorageDead(_34); + _32 = opaque::(move _33) -> [return: bb6, unwind continue]; } bb6: { + StorageDead(_33); StorageDead(_32); - StorageDead(_31); - StorageLive(_34); StorageLive(_35); - _35 = copy _1; StorageLive(_36); _36 = copy _1; -- _34 = Pair(move _35, move _36); -+ _34 = copy _28; - StorageDead(_36); - StorageDead(_35); StorageLive(_37); + _37 = copy _1; +- _35 = Pair(move _36, move _37); ++ _35 = copy _29; + StorageDead(_37); + StorageDead(_36); StorageLive(_38); StorageLive(_39); -- _39 = move _34; -- _38 = move _39 as u16 (Transmute); -+ _39 = copy _28; -+ _38 = copy _28 as u16 (Transmute); - StorageDead(_39); - _37 = opaque::(move _38) -> [return: bb7, unwind continue]; + StorageLive(_40); +- _40 = move _35; +- _39 = move _40 as u16 (Transmute); ++ _40 = copy _29; ++ _39 = copy _29 as u16 (Transmute); + StorageDead(_40); + _38 = opaque::(move _39) -> [return: bb7, unwind continue]; } bb7: { + StorageDead(_39); StorageDead(_38); - StorageDead(_37); +- StorageLive(_41); ++ nop; + StorageLive(_42); + _42 = copy _1; +- _41 = (move _42,); ++ _41 = (copy _1,); + StorageDead(_42); + StorageLive(_43); + StorageLive(_44); + StorageLive(_45); + _45 = copy _41; +- _44 = move _45 as u16 (Transmute); ++ _44 = copy _1; + StorageDead(_45); +- _43 = opaque::(move _44) -> [return: bb8, unwind continue]; ++ _43 = opaque::(copy _1) -> [return: bb8, unwind continue]; + } + + bb8: { + StorageDead(_44); + StorageDead(_43); +- StorageLive(_46); ++ nop; + StorageLive(_47); + _47 = copy _1; +- _46 = [move _47]; ++ _46 = [copy _1]; + StorageDead(_47); + StorageLive(_48); + StorageLive(_49); + StorageLive(_50); + _50 = copy _46; +- _49 = move _50 as u16 (Transmute); ++ _49 = copy _1; + StorageDead(_50); +- _48 = opaque::(move _49) -> [return: bb9, unwind continue]; ++ _48 = opaque::(copy _1) -> [return: bb9, unwind continue]; + } + + bb9: { + StorageDead(_49); + StorageDead(_48); +- StorageLive(_51); ++ nop; + StorageLive(_52); + _52 = copy _2; + StorageLive(_53); +- _53 = (); +- _51 = *const i32 from (move _52, move _53); ++ _53 = const (); ++ _51 = *const i32 from (copy _2, const ()); + StorageDead(_53); + StorageDead(_52); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); + _56 = copy _51; +- _55 = move _56 as *const u8 (Transmute); ++ _55 = copy _2; + StorageDead(_56); +- _54 = opaque::<*const u8>(move _55) -> [return: bb10, unwind continue]; ++ _54 = opaque::<*const u8>(copy _2) -> [return: bb10, unwind continue]; + } + + bb10: { + StorageDead(_55); + StorageDead(_54); _0 = const (); - StorageDead(_34); -- StorageDead(_28); +- StorageDead(_51); +- StorageDead(_46); +- StorageDead(_41); + nop; - StorageDead(_23); -- StorageDead(_18); -- StorageDead(_13); -- StorageDead(_7); -- StorageDead(_2); ++ nop; ++ nop; + StorageDead(_35); +- StorageDead(_29); ++ nop; + StorageDead(_24); +- StorageDead(_19); +- StorageDead(_14); +- StorageDead(_8); +- StorageDead(_3); + nop; + nop; + nop; diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 17357fed5a59e..c895a5792595e 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -933,7 +933,7 @@ fn cast_pointer_eq(p1: *mut u8, p2: *mut u32, p3: *mut u32, p4: *mut [u32]) { // CHECK: _0 = const (); } -unsafe fn aggregate_struct_then_transmute(id: u16) { +unsafe fn aggregate_struct_then_transmute(id: u16, thin: *const u8) { // CHECK: opaque::(copy _1) let a = MyId(id); opaque(std::intrinsics::transmute::<_, u16>(a)); @@ -969,6 +969,18 @@ unsafe fn aggregate_struct_then_transmute(id: u16) { // CHECK: opaque::(move [[TEMP]]) let g = Pair(id, id); opaque(std::intrinsics::transmute_unchecked::<_, u16>(g)); + + // CHECK: opaque::(copy _1) + let h = (id,); + opaque(std::intrinsics::transmute::<_, u16>(h)); + + // CHECK: opaque::(copy _1) + let i = [id]; + opaque(std::intrinsics::transmute::<_, u16>(i)); + + // CHECK: opaque::<*const u8>(copy _2) + let j: *const i32 = std::intrinsics::aggregate_raw_ptr(thin, ()); + opaque(std::intrinsics::transmute::<_, *const u8>(j)); } unsafe fn transmute_then_transmute_again(a: u32, c: char) { From 326fedf3097e1e2974491318c0266f9c11577b21 Mon Sep 17 00:00:00 2001 From: Noa Date: Wed, 8 Jan 2025 22:43:09 -0600 Subject: [PATCH 132/189] Add Pin::as_deref_mut to relnotes --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index 7c2c2406e9062..13102734a8c1f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -60,6 +60,7 @@ Stabilized APIs - [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html) - [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html) - [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html) +- [`Pin::as_deref_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.as_deref_mut) These APIs are now stable in const contexts From 7833cf7a4703099d32012848f682c1e7decc0f51 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 5 Dec 2024 17:32:26 +0000 Subject: [PATCH 133/189] Make `lit_to_mir_constant` infallible --- .../src/builder/expr/as_constant.rs | 52 ++++++++----------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 177c1e33a83bb..e4e452aff7553 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -3,13 +3,12 @@ use rustc_abi::Size; use rustc_ast as ast; use rustc_hir::LangItem; -use rustc_middle::mir::interpret::{ - Allocation, CTFE_ALLOC_SALT, LitToConstError, LitToConstInput, Scalar, -}; +use rustc_middle::mir::interpret::{Allocation, CTFE_ALLOC_SALT, LitToConstInput, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{ - self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex, + self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt as _, + UserTypeAnnotationIndex, }; use rustc_middle::{bug, mir, span_bug}; use tracing::{instrument, trace}; @@ -50,16 +49,7 @@ pub(crate) fn as_constant_inner<'tcx>( let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { ExprKind::Literal { lit, neg } => { - let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) - { - Ok(c) => c, - Err(LitToConstError::Reported(guar)) => { - Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)) - } - Err(LitToConstError::TypeError) => { - bug!("encountered type error in `lit_to_mir_constant`") - } - }; + let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }); ConstOperand { span, user_ty: None, const_ } } @@ -108,11 +98,13 @@ pub(crate) fn as_constant_inner<'tcx>( } #[instrument(skip(tcx, lit_input))] -fn lit_to_mir_constant<'tcx>( - tcx: TyCtxt<'tcx>, - lit_input: LitToConstInput<'tcx>, -) -> Result, LitToConstError> { +fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> { let LitToConstInput { lit, ty, neg } = lit_input; + + if let Err(guar) = ty.error_reported() { + return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); + } + let trunc = |n| { let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { Ok(layout) => layout.size, @@ -123,7 +115,7 @@ fn lit_to_mir_constant<'tcx>( trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); - Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) + ConstValue::Scalar(Scalar::from_uint(result, width)) }; let value = match (lit, ty.kind()) { @@ -154,20 +146,18 @@ fn lit_to_mir_constant<'tcx>( ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) } (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { - trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })? - } - (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg) - .ok_or_else(|| { - LitToConstError::Reported( - tcx.dcx() - .delayed_bug(format!("couldn't parse float literal: {:?}", lit_input.lit)), - ) - })?, + trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }) + } + (ast::LitKind::Float(n, _), ty::Float(fty)) => { + parse_float_into_constval(*n, *fty, neg).unwrap() + } (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)), - _ => return Err(LitToConstError::TypeError), + (ast::LitKind::Err(guar), _) => { + return Const::Ty(Ty::new_error(tcx, *guar), ty::Const::new_error(tcx, *guar)); + } + _ => bug!("invalid lit/ty combination in `lit_to_mir_constant`: {lit:?}: {ty:?}"), }; - Ok(Const::Val(value, ty)) + Const::Val(value, ty) } From 787af97babcb911f2ce70d3d28959cdccc7901bd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 7 Jan 2025 12:03:28 +0000 Subject: [PATCH 134/189] Use error constant instead of explicit error handling --- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 3 --- compiler/rustc_middle/src/mir/interpret/mod.rs | 2 -- compiler/rustc_mir_build/src/thir/constant.rs | 6 +++--- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 1 - compiler/rustc_ty_utils/src/consts.rs | 1 - 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 0a41dad0dd837..5a65d5bafeec3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2456,9 +2456,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { LitToConstInput { lit: &lit.node, ty, neg: negated }; let ct = match tcx.lit_to_const(lit_input) { Ok(c) => c, - Err(LitToConstError::Reported(err)) => { - ty::Const::new_error(tcx, err) - } Err(LitToConstError::TypeError) => todo!(), }; (ct, ty) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 8d73c9e76de1a..040390cb0aedb 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -16,7 +16,6 @@ use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size}; use rustc_ast::{LitKind, Mutability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; -use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; @@ -91,7 +90,6 @@ pub enum LitToConstError { /// This is used for graceful error handling (`span_delayed_bug`) in /// type checking (`Const::from_anon_const`). TypeError, - Reported(ErrorGuaranteed), } #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index ce1c635d1b9f5..0e4efbdcbb029 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -62,13 +62,13 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(*n, *fty, neg).ok_or_else(|| { + let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| { tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) - })?; + }); ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), - (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)), + (ast::LitKind::Err(guar), _) => return Ok(ty::Const::new_error(tcx, *guar)), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 242b62dfa8dde..8216f0a1ba29c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -671,7 +671,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind, - Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 637e239a57010..406e23eb879bb 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -120,7 +120,6 @@ fn recurse_build<'tcx>( let sp = node.span; match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { Ok(c) => c, - Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar), Err(LitToConstError::TypeError) => { bug!("encountered type error in lit_to_const") } From 07fcead0732d9460978dd3b428cd5edcfa299f9a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 7 Jan 2025 12:33:32 +0000 Subject: [PATCH 135/189] Always take the `Ok` path in `lit_to_const` and produce error constants instead --- .../src/hir_ty_lowering/mod.rs | 17 ++----- compiler/rustc_mir_build/src/thir/constant.rs | 2 +- tests/crashes/114317.rs | 6 --- tests/crashes/126182.rs | 10 ---- .../generic_const_exprs/lit_type_mismatch.rs | 22 +++++++++ .../lit_type_mismatch.stderr | 21 ++++++++ .../invalid-patterns.32bit.stderr | 48 +++++++++---------- .../invalid-patterns.64bit.stderr | 48 +++++++++---------- tests/ui/repeat-expr/repeat_count.stderr | 12 ++--- 9 files changed, 103 insertions(+), 83 deletions(-) delete mode 100644 tests/crashes/114317.rs delete mode 100644 tests/crashes/126182.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5a65d5bafeec3..6ed5f92e99511 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2265,18 +2265,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Some(lit_input) = lit_input { // If an error occurred, ignore that it's a literal and leave reporting the error up to // mir. - match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return Some(c), - Err(_) if lit_input.ty.has_aliases() => { - // allow the `ty` to be an alias type, though we cannot handle it here - return None; - } - Err(e) => { - tcx.dcx().span_delayed_bug( - expr.span, - format!("try_lower_anon_const_lit: couldn't lit_to_const {e:?}"), - ); - } + + // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through + // the more expensive anon const code path. + if !lit_input.ty.has_aliases() { + return Some(tcx.at(expr.span).lit_to_const(lit_input).unwrap()); } } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 0e4efbdcbb029..82830562c031a 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -69,7 +69,7 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), (ast::LitKind::Err(guar), _) => return Ok(ty::Const::new_error(tcx, *guar)), - _ => return Err(LitToConstError::TypeError), + _ => return Ok(ty::Const::new_misc_error(tcx)), }; Ok(ty::Const::new_value(tcx, valtree, ty)) diff --git a/tests/crashes/114317.rs b/tests/crashes/114317.rs deleted file mode 100644 index 09fd2beeba8a5..0000000000000 --- a/tests/crashes/114317.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #114317 -#![feature(generic_const_exprs)] - -struct A; - -fn main() {} diff --git a/tests/crashes/126182.rs b/tests/crashes/126182.rs deleted file mode 100644 index 2219a6cb5fa19..0000000000000 --- a/tests/crashes/126182.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: rust-lang/rust#126182 - -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -struct Cond; - -struct Thing>(T); - -impl Thing {} diff --git a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs new file mode 100644 index 0000000000000..1ed0965e1bde1 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs @@ -0,0 +1,22 @@ +//! ICE regression test for #114317 and #126182 +//! Type mismatches of literals cause errors int typeck, +//! but those errors cannot be propagated to the various +//! `lit_to_const` call sites. Now `lit_to_const` just delays +//! a bug and produces an error constant on its own. + +#![feature(adt_const_params)] +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct A(C); +//~^ ERROR: generic parameters with a default must be trailing +//~| ERROR: mismatched types + +struct Cond; + +struct Thing>(T); +//~^ ERROR: mismatched types + +impl Thing {} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr new file mode 100644 index 0000000000000..e4613e498b275 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr @@ -0,0 +1,21 @@ +error: generic parameters with a default must be trailing + --> $DIR/lit_type_mismatch.rs:11:16 + | +LL | struct A(C); + | ^ + +error[E0308]: mismatched types + --> $DIR/lit_type_mismatch.rs:11:24 + | +LL | struct A(C); + | ^ expected `()`, found integer + +error[E0308]: mismatched types + --> $DIR/lit_type_mismatch.rs:17:23 + | +LL | struct Thing>(T); + | ^ expected `bool`, found integer + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index be92429e3abc5..11a824ba73b2a 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -1,27 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:29:21 - | -LL | get_flag::(); - | ^^^^ expected `char`, found `u8` - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:14 - | -LL | get_flag::<7, 'c'>(); - | ^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 - | -LL | get_flag::<42, 0x5ad>(); - | ^^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:18 - | -LL | get_flag::<42, 0x5ad>(); - | ^^^^^ expected `char`, found `u8` - error[E0080]: evaluation of constant value failed --> $DIR/invalid-patterns.rs:38:32 | @@ -56,6 +32,30 @@ error[E0080]: evaluation of constant value failed LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:29:21 + | +LL | get_flag::(); + | ^^^^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:31:14 + | +LL | get_flag::<7, 'c'>(); + | ^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ expected `char`, found `u8` + error: aborting due to 8 previous errors Some errors have detailed explanations: E0080, E0308. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index be92429e3abc5..11a824ba73b2a 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -1,27 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:29:21 - | -LL | get_flag::(); - | ^^^^ expected `char`, found `u8` - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:14 - | -LL | get_flag::<7, 'c'>(); - | ^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 - | -LL | get_flag::<42, 0x5ad>(); - | ^^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:18 - | -LL | get_flag::<42, 0x5ad>(); - | ^^^^^ expected `char`, found `u8` - error[E0080]: evaluation of constant value failed --> $DIR/invalid-patterns.rs:38:32 | @@ -56,6 +32,30 @@ error[E0080]: evaluation of constant value failed LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:29:21 + | +LL | get_flag::(); + | ^^^^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:31:14 + | +LL | get_flag::<7, 'c'>(); + | ^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ expected `char`, found `u8` + error: aborting due to 8 previous errors Some errors have detailed explanations: E0080, E0308. diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index 350ac287507a3..c4aebfb0e20d6 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -15,6 +15,12 @@ error[E0308]: mismatched types LL | let b = [0; ()]; | ^^ expected `usize`, found `()` +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:31:17 + | +LL | let g = [0; G { g: () }]; + | ^^^^^^^^^^^ expected `usize`, found `G` + error[E0308]: mismatched types --> $DIR/repeat_count.rs:10:17 | @@ -33,12 +39,6 @@ error[E0308]: mismatched types LL | let e = [0; "foo"]; | ^^^^^ expected `usize`, found `&str` -error[E0308]: mismatched types - --> $DIR/repeat_count.rs:31:17 - | -LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found `G` - error[E0308]: mismatched types --> $DIR/repeat_count.rs:19:17 | From 8505904dccfb624e663aef3d50f2e5cefefa73d1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 7 Jan 2025 15:14:46 +0000 Subject: [PATCH 136/189] Remove the now-useless `Result` from `lit_to_const` --- .../src/hir_ty_lowering/mod.rs | 9 +++------ compiler/rustc_middle/src/mir/interpret/mod.rs | 9 --------- compiler/rustc_middle/src/query/erase.rs | 9 --------- compiler/rustc_middle/src/query/mod.rs | 4 ++-- compiler/rustc_mir_build/src/thir/constant.rs | 18 +++++++++--------- .../rustc_mir_build/src/thir/pattern/mod.rs | 8 +++----- compiler/rustc_ty_utils/src/consts.rs | 9 ++------- 7 files changed, 19 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 6ed5f92e99511..511ecc06e7966 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -35,7 +35,7 @@ use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; -use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ @@ -2269,7 +2269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through // the more expensive anon const code path. if !lit_input.ty.has_aliases() { - return Some(tcx.at(expr.span).lit_to_const(lit_input).unwrap()); + return Some(tcx.at(expr.span).lit_to_const(lit_input)); } } @@ -2447,10 +2447,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::PatExprKind::Lit { lit, negated } => { let lit_input = LitToConstInput { lit: &lit.node, ty, neg: negated }; - let ct = match tcx.lit_to_const(lit_input) { - Ok(c) => c, - Err(LitToConstError::TypeError) => todo!(), - }; + let ct = tcx.lit_to_const(lit_input); (ct, ty) } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 040390cb0aedb..b88137544bca3 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -83,15 +83,6 @@ pub struct LitToConstInput<'tcx> { pub neg: bool, } -/// Error type for `tcx.lit_to_const`. -#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)] -pub enum LitToConstError { - /// The literal's inferred type did not match the expected `ty` in the input. - /// This is used for graceful error handling (`span_delayed_bug`) in - /// type checking (`Const::from_anon_const`). - TypeError, -} - #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct AllocId(pub NonZero); diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b72c0e776fe90..1676afb4b6ec4 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -141,14 +141,6 @@ impl EraseType for Result>, &ty::layout::Layou >()]; } -impl EraseType for Result, mir::interpret::LitToConstError> { - type Result = [u8; size_of::, mir::interpret::LitToConstError>>()]; -} - -impl EraseType for Result, mir::interpret::LitToConstError> { - type Result = [u8; size_of::, mir::interpret::LitToConstError>>()]; -} - impl EraseType for Result, mir::interpret::ErrorHandled> { type Result = [u8; size_of::, mir::interpret::ErrorHandled>>()]; } @@ -296,7 +288,6 @@ trivial! { rustc_middle::mir::interpret::AllocId, rustc_middle::mir::interpret::CtfeProvenance, rustc_middle::mir::interpret::ErrorHandled, - rustc_middle::mir::interpret::LitToConstError, rustc_middle::thir::ExprId, rustc_middle::traits::CodegenObligationError, rustc_middle::traits::EvaluationResult, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 95995b956cda5..283675573d4e5 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -57,7 +57,7 @@ use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, use crate::middle::stability::{self, DeprecationEntry}; use crate::mir::interpret::{ EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, - EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput, + EvalToValTreeResult, GlobalId, LitToConstInput, }; use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem}; use crate::query::erase::{Erase, erase, restore}; @@ -1268,7 +1268,7 @@ rustc_queries! { // FIXME get rid of this with valtrees query lit_to_const( key: LitToConstInput<'tcx> - ) -> Result, LitToConstError> { + ) -> ty::Const<'tcx> { desc { "converting literal to const" } } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 82830562c031a..49db522cf0eed 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_hir::LangItem; use rustc_middle::bug; -use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _}; use tracing::trace; @@ -10,11 +10,11 @@ use crate::builder::parse_float_into_scalar; pub(crate) fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, -) -> Result, LitToConstError> { +) -> ty::Const<'tcx> { let LitToConstInput { lit, ty, neg } = lit_input; if let Err(guar) = ty.error_reported() { - return Ok(ty::Const::new_error(tcx, guar)); + return ty::Const::new_error(tcx, guar); } let trunc = |n| { @@ -28,8 +28,8 @@ pub(crate) fn lit_to_const<'tcx>( let result = width.truncate(n); trace!("trunc result: {}", result); - Ok(ScalarInt::try_from_uint(result, width) - .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))) + ScalarInt::try_from_uint(result, width) + .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)) }; let valtree = match (lit, ty.kind()) { @@ -57,7 +57,7 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { let scalar_int = - trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })?; + trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }); ty::ValTree::from_scalar_int(scalar_int) } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), @@ -68,9 +68,9 @@ pub(crate) fn lit_to_const<'tcx>( ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), - (ast::LitKind::Err(guar), _) => return Ok(ty::Const::new_error(tcx, *guar)), - _ => return Ok(ty::Const::new_misc_error(tcx)), + (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, *guar), + _ => return ty::Const::new_misc_error(tcx), }; - Ok(ty::Const::new_value(tcx, valtree, ty)) + ty::Const::new_value(tcx, valtree, ty) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8216f0a1ba29c..44b038bb5faf1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -13,7 +13,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd}; use rustc_index::Idx; use rustc_lint as lint; -use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::thir::{ Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; @@ -669,10 +669,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let ct_ty = self.typeck_results.node_type(expr.hir_id); let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; - match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind, - Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), - } + let constant = self.tcx.at(expr.span).lit_to_const(lit_input); + self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind } } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 406e23eb879bb..51a7c976f600c 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -4,7 +4,7 @@ use rustc_abi::{FIRST_VARIANT, VariantIdx}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::query::Providers; use rustc_middle::thir::visit; use rustc_middle::thir::visit::Visitor; @@ -118,12 +118,7 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { - Ok(c) => c, - Err(LitToConstError::TypeError) => { - bug!("encountered type error in lit_to_const") - } - } + tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(lit); From 84c8d4f52d5be135e2dec89379cb1d0f67be648c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 8 Jan 2025 12:40:02 +0000 Subject: [PATCH 137/189] Use option combinators instead of manual if/return --- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 511ecc06e7966..cb90fff782fb0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2262,18 +2262,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { _ => None, }; - if let Some(lit_input) = lit_input { - // If an error occurred, ignore that it's a literal and leave reporting the error up to - // mir. - + lit_input // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through // the more expensive anon const code path. - if !lit_input.ty.has_aliases() { - return Some(tcx.at(expr.span).lit_to_const(lit_input)); - } - } - - None + .filter(|l| !l.ty.has_aliases()) + .map(|l| tcx.at(expr.span).lit_to_const(l)) } fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { From be92ac3567e4a808cc08cd909efa5663fff2f8ea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 8 Jan 2025 08:53:10 +0000 Subject: [PATCH 138/189] Only treat plain literal patterns as short --- src/tools/rustfmt/src/patterns.rs | 37 +++++++++++++++-------- src/tools/rustfmt/tests/source/pattern.rs | 10 ++++++ src/tools/rustfmt/tests/target/pattern.rs | 8 +++++ 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index b55469f332aa1..1d88726d94586 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -31,18 +31,31 @@ use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident}; /// - `[small, ntp]` /// - unary tuple constructor `([small, ntp])` /// - `&[small]` -pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { +pub(crate) fn is_short_pattern( + context: &RewriteContext<'_>, + pat: &ast::Pat, + pat_str: &str, +) -> bool { // We also require that the pattern is reasonably 'small' with its literal width. - pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat) + pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(context, pat) } -fn is_short_pattern_inner(pat: &ast::Pat) -> bool { - match pat.kind { - ast::PatKind::Rest - | ast::PatKind::Never - | ast::PatKind::Wild - | ast::PatKind::Err(_) - | ast::PatKind::Expr(_) => true, +fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool { + match &pat.kind { + ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => { + true + } + ast::PatKind::Expr(expr) => match &expr.kind { + ast::ExprKind::Lit(_) => true, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind { + ast::ExprKind::Lit(_) => true, + _ => unreachable!(), + }, + ast::ExprKind::ConstBlock(_) | ast::ExprKind::Path(..) => { + context.config.style_edition() <= StyleEdition::Edition2024 + } + _ => unreachable!(), + }, ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -57,8 +70,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool { ast::PatKind::Box(ref p) | PatKind::Deref(ref p) | ast::PatKind::Ref(ref p, _) - | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p), - PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)), + | ast::PatKind::Paren(ref p) => is_short_pattern_inner(context, &*p), + PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(context, p)), } } @@ -96,7 +109,7 @@ impl Rewrite for Pat { let use_mixed_layout = pats .iter() .zip(pat_strs.iter()) - .all(|(pat, pat_str)| is_short_pattern(pat, pat_str)); + .all(|(pat, pat_str)| is_short_pattern(context, pat, pat_str)); let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect(); let tactic = if use_mixed_layout { DefinitiveListTactic::Mixed diff --git a/src/tools/rustfmt/tests/source/pattern.rs b/src/tools/rustfmt/tests/source/pattern.rs index f06d03cadf2f7..ed6ad690fa98d 100644 --- a/src/tools/rustfmt/tests/source/pattern.rs +++ b/src/tools/rustfmt/tests/source/pattern.rs @@ -88,3 +88,13 @@ fn issue3728() { | c; foo((1,)); } + +fn literals() { + match 42 { + const { 1 + 2 } | 4 + | 6 => {} + 10 | 11 | 12 + | 13 | 14 => {} + _ => {} + } +} \ No newline at end of file diff --git a/src/tools/rustfmt/tests/target/pattern.rs b/src/tools/rustfmt/tests/target/pattern.rs index 576018ac623fd..e867f65929dd9 100644 --- a/src/tools/rustfmt/tests/target/pattern.rs +++ b/src/tools/rustfmt/tests/target/pattern.rs @@ -96,3 +96,11 @@ fn issue3728() { let foo = |(c,)| c; foo((1,)); } + +fn literals() { + match 42 { + const { 1 + 2 } | 4 | 6 => {} + 10 | 11 | 12 | 13 | 14 => {} + _ => {} + } +} From 916a0b322536821ea210905a7dd8294d10d0271b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:24:27 +0000 Subject: [PATCH 139/189] Minor cleanup --- build_system/build_sysroot.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index e47e982991622..33759946909f3 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -102,19 +102,14 @@ pub(crate) fn build_sysroot( .install_into_sysroot(dist_dir); } - let mut target_compiler = { - let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")); - let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")); - - Compiler { - cargo: bootstrap_host_compiler.cargo.clone(), - rustc: rustc_clif.clone(), - rustdoc: rustdoc_clif.clone(), - rustflags: vec![], - rustdocflags: vec![], - triple: target_triple, - runner: vec![], - } + let mut target_compiler = Compiler { + cargo: bootstrap_host_compiler.cargo.clone(), + rustc: dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")), + rustdoc: dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")), + rustflags: vec![], + rustdocflags: vec![], + triple: target_triple, + runner: vec![], }; if !is_native { target_compiler.set_cross_linker_and_runner(); From 0e8e9b38878f1f30f53a7445a752783c7de38583 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:26:50 +0000 Subject: [PATCH 140/189] Put rustc_codegen_cranelift.dll in bin rather than lib on Windows rustc-clif has long been changed from a custom driver linking against cg_clif to a wrapper around rustc which passes -Zcodegen-backend. --- build_system/build_sysroot.rs | 9 +-------- scripts/cargo-clif.rs | 2 +- scripts/rustc-clif.rs | 2 +- scripts/rustdoc-clif.rs | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 33759946909f3..a73e3c87d43d0 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -33,14 +33,7 @@ pub(crate) fn build_sysroot( let cg_clif_dylib_path = match cg_clif_dylib_src { CodegenBackend::Local(src_path) => { // Copy the backend - let cg_clif_dylib_path = if cfg!(windows) { - // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the - // binaries. - dist_dir.join("bin") - } else { - dist_dir.join("lib") - } - .join(src_path.file_name().unwrap()); + let cg_clif_dylib_path = dist_dir.join("lib").join(src_path.file_name().unwrap()); try_hard_link(src_path, &cg_clif_dylib_path); CodegenBackend::Local(cg_clif_dylib_path) } diff --git a/scripts/cargo-clif.rs b/scripts/cargo-clif.rs index 1e14f41d4a2c2..ebbb687961058 100644 --- a/scripts/cargo-clif.rs +++ b/scripts/cargo-clif.rs @@ -16,7 +16,7 @@ fn main() { if let Some(name) = option_env!("BUILTIN_BACKEND") { rustflags.push(format!("-Zcodegen-backend={name}")); } else { - let dylib = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join( + let dylib = sysroot.join("lib").join( env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX, diff --git a/scripts/rustc-clif.rs b/scripts/rustc-clif.rs index a27b9983bf181..528031af82a84 100644 --- a/scripts/rustc-clif.rs +++ b/scripts/rustc-clif.rs @@ -11,7 +11,7 @@ fn main() { sysroot = sysroot.parent().unwrap(); } - let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join( + let cg_clif_dylib_path = sysroot.join("lib").join( env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX, ); diff --git a/scripts/rustdoc-clif.rs b/scripts/rustdoc-clif.rs index 1cad312bb7918..6ebe060d8bbd1 100644 --- a/scripts/rustdoc-clif.rs +++ b/scripts/rustdoc-clif.rs @@ -11,7 +11,7 @@ fn main() { sysroot = sysroot.parent().unwrap(); } - let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join( + let cg_clif_dylib_path = sysroot.join("lib").join( env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX, ); From 517118e1600899a08a997364efe209229c410c03 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:00:00 +0000 Subject: [PATCH 141/189] Make it easier to use unreleased versions of Cranelift --- Cargo.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 82d2b6cb2c4ce..bfdbc3e768a69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,14 @@ libloading = { version = "0.8.0", optional = true } smallvec = "1.8.1" [patch.crates-io] +# Uncomment to use an unreleased version of cranelift +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" } + # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" } From f6d58eb790a4b7e3e1fccb8caa4f684cb46af7bf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:03:15 +0000 Subject: [PATCH 142/189] Update dependencies --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec71370ef9e7e..b5aba86079fc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,15 +10,15 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" [[package]] name = "bitflags" @@ -211,9 +211,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "gimli" @@ -253,15 +253,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets", @@ -290,9 +290,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "hashbrown 0.15.2", @@ -311,9 +311,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -346,9 +346,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc_codegen_cranelift" @@ -370,18 +370,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -402,9 +402,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -419,9 +419,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" From 39daadc76ebdb97e0acf242791be129ae1003e16 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 8 Jan 2025 17:31:40 +0000 Subject: [PATCH 143/189] Account for identity substituted items in symbol mangling --- .../src/ty/normalize_erasing_regions.rs | 12 ++-- compiler/rustc_symbol_mangling/src/legacy.rs | 56 +++++++++++++------ compiler/rustc_symbol_mangling/src/v0.rs | 55 ++++++++++++------ tests/coverage/generic-unused-impl.cov-map | 18 ++++++ tests/coverage/generic-unused-impl.coverage | 17 ++++++ tests/coverage/generic-unused-impl.rs | 16 ++++++ 6 files changed, 135 insertions(+), 39 deletions(-) create mode 100644 tests/coverage/generic-unused-impl.cov-map create mode 100644 tests/coverage/generic-unused-impl.coverage create mode 100644 tests/coverage/generic-unused-impl.rs diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index f611b69905c9c..e86e01451fefb 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -165,10 +165,14 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let arg = self.typing_env.as_query_input(arg); - self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( - "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", - arg.value - )) + self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| { + bug!( + "Failed to normalize {:?} in typing_env={:?}, \ + maybe try to call `try_normalize_erasing_regions` instead", + arg.value, + self.typing_env, + ) + }) } } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 333ea0214eb3f..58c0a05df1f2c 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -8,7 +8,6 @@ use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; use rustc_middle::ty::{ self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt, - TypingEnv, }; use tracing::debug; @@ -387,23 +386,44 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { ) -> Result<(), PrintError> { let self_ty = self.tcx.type_of(impl_def_id); let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); - let (typing_env, mut self_ty, mut impl_trait_ref) = - if self.tcx.generics_of(impl_def_id).count() <= args.len() { - ( - TypingEnv::fully_monomorphized(), - self_ty.instantiate(self.tcx, args), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), - ) - } else { - // We are probably printing a nested item inside of an impl. - // Use the identity substitutions for the impl. We also need - // a well-formed param-env, so let's use post-analysis. - ( - TypingEnv::post_analysis(self.tcx, impl_def_id), - self_ty.instantiate_identity(), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), - ) - }; + let generics = self.tcx.generics_of(impl_def_id); + // We have two cases to worry about here: + // 1. We're printing a nested item inside of an impl item, like an inner + // function inside of a method. Due to the way that def path printing works, + // we'll render this something like `::method::inner_fn` + // but we have no substs for this impl since it's not really inheriting + // generics from the outer item. We need to use the identity substs, and + // to normalize we need to use the correct param-env too. + // 2. We're mangling an item with identity substs. This seems to only happen + // when generating coverage, since we try to generate coverage for unused + // items too, and if something isn't monomorphized then we necessarily don't + // have anything to substitute the instance with. + // NOTE: We don't support mangling partially substituted but still polymorphic + // instances, like `impl Tr for ()` where `A` is substituted w/ `(T,)`. + let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len() + || &args[..generics.count()] + == self + .tcx + .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .as_slice() + { + ( + ty::TypingEnv::post_analysis(self.tcx, impl_def_id), + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + } else { + assert!( + !args.has_non_region_param(), + "should not be mangling partially substituted \ + polymorphic instance: {impl_def_id:?} {args:?}" + ); + ( + ty::TypingEnv::fully_monomorphized(), + self_ty.instantiate(self.tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), + ) + }; match &mut impl_trait_ref { Some(impl_trait_ref) => { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index b77ad209e2bd8..4ddf530a00d4a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -233,23 +233,44 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let self_ty = self.tcx.type_of(impl_def_id); let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); - let (typing_env, mut self_ty, mut impl_trait_ref) = - if self.tcx.generics_of(impl_def_id).count() <= args.len() { - ( - ty::TypingEnv::fully_monomorphized(), - self_ty.instantiate(self.tcx, args), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), - ) - } else { - // We are probably printing a nested item inside of an impl. - // Use the identity substitutions for the impl. We also need - // a well-formed param-env, so let's use post-analysis. - ( - ty::TypingEnv::post_analysis(self.tcx, impl_def_id), - self_ty.instantiate_identity(), - impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), - ) - }; + let generics = self.tcx.generics_of(impl_def_id); + // We have two cases to worry about here: + // 1. We're printing a nested item inside of an impl item, like an inner + // function inside of a method. Due to the way that def path printing works, + // we'll render this something like `::method::inner_fn` + // but we have no substs for this impl since it's not really inheriting + // generics from the outer item. We need to use the identity substs, and + // to normalize we need to use the correct param-env too. + // 2. We're mangling an item with identity substs. This seems to only happen + // when generating coverage, since we try to generate coverage for unused + // items too, and if something isn't monomorphized then we necessarily don't + // have anything to substitute the instance with. + // NOTE: We don't support mangling partially substituted but still polymorphic + // instances, like `impl Tr for ()` where `A` is substituted w/ `(T,)`. + let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len() + || &args[..generics.count()] + == self + .tcx + .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .as_slice() + { + ( + ty::TypingEnv::post_analysis(self.tcx, impl_def_id), + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + } else { + assert!( + !args.has_non_region_param(), + "should not be mangling partially substituted \ + polymorphic instance: {impl_def_id:?} {args:?}" + ); + ( + ty::TypingEnv::fully_monomorphized(), + self_ty.instantiate(self.tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), + ) + }; match &mut impl_trait_ref { Some(impl_trait_ref) => { diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map new file mode 100644 index 0000000000000..7cb6d2f385d79 --- /dev/null +++ b/tests/coverage/generic-unused-impl.cov-map @@ -0,0 +1,18 @@ +Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0a, 05, 03, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 10, 5) to (start + 3, 6) +Highest counter ID seen: (none) + +Function name: generic_unused_impl::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 10, 01, 00, 0d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13) +Highest counter ID seen: c0 + diff --git a/tests/coverage/generic-unused-impl.coverage b/tests/coverage/generic-unused-impl.coverage new file mode 100644 index 0000000000000..0c20285f84544 --- /dev/null +++ b/tests/coverage/generic-unused-impl.coverage @@ -0,0 +1,17 @@ + LL| |trait Foo { + LL| | type Assoc; + LL| | + LL| | fn from(s: Self::Assoc) -> Self; + LL| |} + LL| | + LL| |struct W(T); + LL| | + LL| |impl From<[T::Assoc; 1]> for W { + LL| 0| fn from(from: [T::Assoc; 1]) -> Self { + LL| 0| let [item] = from; + LL| 0| W(Foo::from(item)) + LL| 0| } + LL| |} + LL| | + LL| 1|fn main() {} + diff --git a/tests/coverage/generic-unused-impl.rs b/tests/coverage/generic-unused-impl.rs new file mode 100644 index 0000000000000..e44b1ca8a1d74 --- /dev/null +++ b/tests/coverage/generic-unused-impl.rs @@ -0,0 +1,16 @@ +trait Foo { + type Assoc; + + fn from(s: Self::Assoc) -> Self; +} + +struct W(T); + +impl From<[T::Assoc; 1]> for W { + fn from(from: [T::Assoc; 1]) -> Self { + let [item] = from; + W(Foo::from(item)) + } +} + +fn main() {} From b85b2c60f950252d38ce91b0f1ab535333866b3b Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 9 Jan 2025 13:24:16 +0100 Subject: [PATCH 144/189] add comment to test --- tests/coverage/generic-unused-impl.cov-map | 8 ++++---- tests/coverage/generic-unused-impl.coverage | 1 + tests/coverage/generic-unused-impl.rs | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map index 7cb6d2f385d79..5878de231badf 100644 --- a/tests/coverage/generic-unused-impl.cov-map +++ b/tests/coverage/generic-unused-impl.cov-map @@ -1,18 +1,18 @@ Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0a, 05, 03, 06] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 03, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 10, 5) to (start + 3, 6) +- Code(Zero) at (prev + 11, 5) to (start + 3, 6) Highest counter ID seen: (none) Function name: generic_unused_impl::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 10, 01, 00, 0d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 0d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/generic-unused-impl.coverage b/tests/coverage/generic-unused-impl.coverage index 0c20285f84544..c3a3c7242901a 100644 --- a/tests/coverage/generic-unused-impl.coverage +++ b/tests/coverage/generic-unused-impl.coverage @@ -1,3 +1,4 @@ + LL| |// Regression test for #135235. LL| |trait Foo { LL| | type Assoc; LL| | diff --git a/tests/coverage/generic-unused-impl.rs b/tests/coverage/generic-unused-impl.rs index e44b1ca8a1d74..8623138945006 100644 --- a/tests/coverage/generic-unused-impl.rs +++ b/tests/coverage/generic-unused-impl.rs @@ -1,3 +1,4 @@ +// Regression test for #135235. trait Foo { type Assoc; From c74c817fb7da588c236d7368ccac41b47fe1fad8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:41:32 +0000 Subject: [PATCH 145/189] Rustup to rustc 1.86.0-nightly (a580b5c37 2025-01-08) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4b97f21057982..1105b89fbb3ef 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-01-05" +channel = "nightly-2025-01-09" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From ec96e028a79a39fe743ba97aafdb20bdda7df1b5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:28:02 +0000 Subject: [PATCH 146/189] Slightly simplify maybe_codegen_checked --- src/codegen_i128.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/codegen_i128.rs b/src/codegen_i128.rs index 734574338d049..7e260e6d7bdf1 100644 --- a/src/codegen_i128.rs +++ b/src/codegen_i128.rs @@ -79,7 +79,6 @@ pub(crate) fn maybe_codegen_checked<'tcx>( let is_signed = type_sign(lhs.layout().ty); match bin_op { - BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(), BinOp::Add | BinOp::Sub => None, BinOp::Mul => { let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); @@ -98,12 +97,6 @@ pub(crate) fn maybe_codegen_checked<'tcx>( ); Some(out_place.to_cvalue(fx)) } - BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(), - BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(), - BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), - BinOp::Div | BinOp::Rem => unreachable!(), - BinOp::Cmp => unreachable!(), - BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(), - BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(), + _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, lhs, rhs), } } From 8fd8b2d63c25138619dad163131d29c432e295ba Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:04:25 +0000 Subject: [PATCH 147/189] Only handle BinOp::Mul in codegen_i128::maybe_codegen_mul_checked --- src/codegen_i128.rs | 39 ++++++++++++++++----------------------- src/num.rs | 8 ++++---- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/codegen_i128.rs b/src/codegen_i128.rs index 7e260e6d7bdf1..025667e66b2a2 100644 --- a/src/codegen_i128.rs +++ b/src/codegen_i128.rs @@ -62,9 +62,8 @@ pub(crate) fn maybe_codegen<'tcx>( } } -pub(crate) fn maybe_codegen_checked<'tcx>( +pub(crate) fn maybe_codegen_mul_checked<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - bin_op: BinOp, lhs: CValue<'tcx>, rhs: CValue<'tcx>, ) -> Option> { @@ -78,25 +77,19 @@ pub(crate) fn maybe_codegen_checked<'tcx>( let is_signed = type_sign(lhs.layout().ty); - match bin_op { - BinOp::Add | BinOp::Sub => None, - BinOp::Mul => { - let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); - let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); - let param_types = vec![ - AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), - AbiParam::new(types::I128), - AbiParam::new(types::I128), - ]; - let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)]; - fx.lib_call( - if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" }, - param_types, - vec![], - &args, - ); - Some(out_place.to_cvalue(fx)) - } - _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, lhs, rhs), - } + let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); + let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); + let param_types = vec![ + AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), + AbiParam::new(types::I128), + AbiParam::new(types::I128), + ]; + let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)]; + fx.lib_call( + if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" }, + param_types, + vec![], + &args, + ); + Some(out_place.to_cvalue(fx)) } diff --git a/src/num.rs b/src/num.rs index fb18f45d7dcad..0b7273d42b7e9 100644 --- a/src/num.rs +++ b/src/num.rs @@ -200,10 +200,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( let lhs = in_lhs.load_scalar(fx); let rhs = in_rhs.load_scalar(fx); - if let Some(res) = crate::codegen_i128::maybe_codegen_checked(fx, bin_op, in_lhs, in_rhs) { - return res; - } - let signed = type_sign(in_lhs.layout().ty); let (res, has_overflow) = match bin_op { @@ -236,6 +232,10 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( (val, has_overflow) } BinOp::Mul => { + if let Some(res) = crate::codegen_i128::maybe_codegen_mul_checked(fx, in_lhs, in_rhs) { + return res; + } + let ty = fx.bcx.func.dfg.value_type(lhs); match ty { types::I8 | types::I16 | types::I32 if !signed => { From b321cd5573d5bfc4b21f456be146c8d29d67bd1d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Dec 2024 21:04:17 +0000 Subject: [PATCH 148/189] Add note back to conditionally-const error message --- compiler/rustc_const_eval/src/check_consts/ops.rs | 12 ++++++++++-- tests/ui/issues/issue-25901.stderr | 1 + .../arbitrary-self-from-method-substs-ice.stderr | 1 + .../ui/traits/const-traits/cross-crate.stock.stderr | 1 + .../traits/const-traits/cross-crate.stocknc.stderr | 2 ++ .../traits/const-traits/staged-api-user-crate.stderr | 1 + .../const-traits/super-traits-fail-3.nyn.stderr | 1 + .../const-traits/super-traits-fail-3.nyy.stderr | 1 + 8 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index ebd680ac28a2e..55e43f5af3511 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -92,7 +92,7 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx.sess.create_feature_err( + let mut err = ccx.tcx.sess.create_feature_err( errors::ConditionallyConstCall { span, def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args), @@ -100,7 +100,15 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { kind: ccx.const_kind(), }, sym::const_trait_impl, - ) + ); + + err.note(format!( + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + ccx.const_kind(), + )); + + err } } diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr index 655a8b78c6a1e..b100ce30a41b2 100644 --- a/tests/ui/issues/issue-25901.stderr +++ b/tests/ui/issues/issue-25901.stderr @@ -7,6 +7,7 @@ LL | static S: &'static B = &A; = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index cf4c219215e08..5ed82eb764901 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -7,6 +7,7 @@ LL | self.0 = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0493]: destructor of `R` cannot be evaluated at compile-time --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43 diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr index 09bf9c023c843..de73d904f42bf 100644 --- a/tests/ui/traits/const-traits/cross-crate.stock.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr @@ -7,6 +7,7 @@ LL | Const.func(); = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr index e52e5609b01d4..74fa35cfd04d4 100644 --- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr @@ -7,6 +7,7 @@ LL | NonConst.func(); = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0658]: cannot call conditionally-const method `::func` in constant functions --> $DIR/cross-crate.rs:22:5 @@ -17,6 +18,7 @@ LL | Const.func(); = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index bf7466b8e1666..970e0c1252cfb 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -7,6 +7,7 @@ LL | Unstable::func(); = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr index 8abda1c8f8afe..1b1ca4b28a462 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr @@ -47,6 +47,7 @@ LL | x.a(); = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 5 previous errors diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr index 8abda1c8f8afe..1b1ca4b28a462 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr @@ -47,6 +47,7 @@ LL | x.a(); = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 5 previous errors From 5a9f0be0bd7ae663a3084da90eb89dcc5721ec15 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Dec 2024 21:17:36 +0000 Subject: [PATCH 149/189] Make the non-const part swappable in the diagnostic --- compiler/rustc_const_eval/messages.ftl | 59 ++++++++++--------- .../rustc_const_eval/src/check_consts/ops.rs | 16 +++-- compiler/rustc_const_eval/src/errors.rs | 29 ++++++--- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 0c2242b810b69..7c66f5dedb5bc 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -12,8 +12,6 @@ const_eval_already_reported = const_eval_assume_false = `assume` called with `false` -const_eval_await_non_const = - cannot convert `{$ty}` into a future in {const_eval_const_context}s const_eval_bounds_check_failed = indexing out of bounds: the len is {$len} but the index is {$index} const_eval_call_nonzero_intrinsic = @@ -23,9 +21,6 @@ const_eval_closure_call = closures need an RFC before allowed to be called in {const_eval_const_context}s const_eval_closure_fndef_not_const = function defined here, but it is not `const` -const_eval_closure_non_const = - cannot call non-const closure in {const_eval_const_context}s - const_eval_conditionally_const_call = cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s @@ -62,10 +57,6 @@ const_eval_dealloc_incorrect_layout = const_eval_dealloc_kind_mismatch = deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation -const_eval_deref_coercion_non_const = - cannot perform deref coercion on `{$ty}` in {const_eval_const_context}s - .note = attempting to deref into `{$target_ty}` - .target_note = deref defined here const_eval_deref_function_pointer = accessing {$allocation} which contains a function const_eval_deref_vtable_pointer = @@ -109,9 +100,6 @@ const_eval_extern_type_field = `extern type` field does not have a known offset const_eval_fn_ptr_call = function pointers need an RFC before allowed to be called in {const_eval_const_context}s -const_eval_for_loop_into_iter_non_const = - cannot use `for` loop on `{$ty}` in {const_eval_const_context}s - const_eval_frame_note = {$times -> [0] {const_eval_frame_note_inner} *[other] [... {$times} additional calls {const_eval_frame_note_inner} ...] @@ -216,9 +204,6 @@ const_eval_long_running = .label = the const evaluator is currently interpreting this expression .help = the constant being evaluated -const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s - .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es - const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} const_eval_memory_access_test = memory access failed @@ -249,17 +234,46 @@ const_eval_mutable_ref_escaping = If you really want global mutable state, try using an interior mutable `static` or a `static mut`. const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead + +const_eval_non_const_await = + cannot convert `{$ty}` into a future in {const_eval_const_context}s + +const_eval_non_const_closure = + cannot call {$non}-const closure in {const_eval_const_context}s + +const_eval_non_const_deref_coercion = + cannot perform {$non}-const deref coercion on `{$ty}` in {const_eval_const_context}s + .note = attempting to deref into `{$target_ty}` + .target_note = deref defined here + const_eval_non_const_fmt_macro_call = - cannot call non-const formatting macro in {const_eval_const_context}s + cannot call {$non}-const formatting macro in {const_eval_const_context}s const_eval_non_const_fn_call = - cannot call non-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s + cannot call {$non}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s + +const_eval_non_const_for_loop_into_iter = + cannot use `for` loop on `{$ty}` in {const_eval_const_context}s const_eval_non_const_impl = impl defined here, but it is not `const` const_eval_non_const_intrinsic = - cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s + cannot call {$non}-const intrinsic `{$name}` in {const_eval_const_context}s + +const_eval_non_const_match_eq = cannot match on `{$ty}` in {const_eval_const_context}s + .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es + +const_eval_non_const_operator = + cannot call {$non}-const operator in {const_eval_const_context}s + +const_eval_non_const_question_branch = + `?` is not allowed on `{$ty}` in {const_eval_const_context}s +const_eval_non_const_question_from_residual = + `?` is not allowed on `{$ty}` in {const_eval_const_context}s + +const_eval_non_const_try_block_from_output = + `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires @@ -281,8 +295,6 @@ const_eval_offset_from_unsigned_overflow = *[false] offset } than second: {$a_offset} < {$b_offset} -const_eval_operator_non_const = - cannot call non-const operator in {const_eval_const_context}s const_eval_overflow_arith = arithmetic overflow in `{$intrinsic}` const_eval_overflow_shift = @@ -325,11 +337,6 @@ const_eval_ptr_as_bytes_1 = const_eval_ptr_as_bytes_2 = the absolute address of a pointer is not known at compile-time, so such operations are not supported -const_eval_question_branch_non_const = - `?` is not allowed on `{$ty}` in {const_eval_const_context}s -const_eval_question_from_residual_non_const = - `?` is not allowed on `{$ty}` in {const_eval_const_context}s - const_eval_range = in the range {$lo}..={$hi} const_eval_range_lower = greater or equal to {$lo} const_eval_range_singular = equal to {$lo} @@ -379,8 +386,6 @@ const_eval_too_generic = const_eval_too_many_caller_args = calling a function with more arguments than it expected -const_eval_try_block_from_output_non_const = - `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s const_eval_unallowed_heap_allocations = diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 55e43f5af3511..5aa0de9ce8655 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -130,7 +130,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let ConstCx { tcx, typing_env, .. } = *ccx; let caller = ccx.def_id(); - let diag_trait = |err, self_ty: Ty<'_>, trait_id| { + let note_trait_if_possible = |err, self_ty: Ty<'_>, trait_id| { let trait_ref = TraitRef::from_method(tcx, trait_id, args); match self_ty.kind() { @@ -183,6 +183,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { span, ty: self_ty, kind: ccx.const_kind(), + non: "non", }) }; } @@ -226,9 +227,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { span, kind: ccx.const_kind(), note, + non: "non", }); - diag_trait(&mut err, self_ty, fn_trait_id); + note_trait_if_possible(&mut err, self_ty, fn_trait_id); err } CallKind::Operator { trait_id, self_ty, .. } => { @@ -237,6 +239,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { span, kind: ccx.const_kind(), ty: self_ty, + non: "non", }) } else { let mut sugg = None; @@ -282,10 +285,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { span, kind: ccx.const_kind(), sugg, + non: "non", }) }; - diag_trait(&mut err, self_ty, trait_id); + note_trait_if_possible(&mut err, self_ty, trait_id); err } CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { @@ -302,19 +306,21 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { kind: ccx.const_kind(), target_ty: deref_target_ty, deref_target: target, + non: "non", }); - diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); + note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { - ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }) + ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind(), non: "non" }) } _ => ccx.dcx().create_err(errors::NonConstFnCall { span, def_descr: ccx.tcx.def_descr(callee), def_path_str: ccx.tcx.def_path_str_with_args(callee, args), kind: ccx.const_kind(), + non: "non", }), }; diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 57534540019bb..8e105f9beec96 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -174,6 +174,7 @@ pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] @@ -194,6 +195,7 @@ pub(crate) struct NonConstFnCall { pub def_path_str: String, pub def_descr: &'static str, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] @@ -293,68 +295,75 @@ pub struct RawBytesNote { // FIXME(fee1-dead) do not use stringly typed `ConstContext` #[derive(Diagnostic)] -#[diag(const_eval_match_eq_non_const, code = E0015)] +#[diag(const_eval_non_const_match_eq, code = E0015)] #[note] pub struct NonConstMatchEq<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_for_loop_into_iter_non_const, code = E0015)] +#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)] pub struct NonConstForLoopIntoIter<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_question_branch_non_const, code = E0015)] +#[diag(const_eval_non_const_question_branch, code = E0015)] pub struct NonConstQuestionBranch<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_question_from_residual_non_const, code = E0015)] +#[diag(const_eval_non_const_question_from_residual, code = E0015)] pub struct NonConstQuestionFromResidual<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_try_block_from_output_non_const, code = E0015)] +#[diag(const_eval_non_const_try_block_from_output, code = E0015)] pub struct NonConstTryBlockFromOutput<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_await_non_const, code = E0015)] +#[diag(const_eval_non_const_await, code = E0015)] pub struct NonConstAwait<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_closure_non_const, code = E0015)] +#[diag(const_eval_non_const_closure, code = E0015)] pub struct NonConstClosure { #[primary_span] pub span: Span, pub kind: ConstContext, #[subdiagnostic] pub note: Option, + pub non: &'static str, } #[derive(Subdiagnostic)] @@ -381,17 +390,18 @@ pub struct ConsiderDereferencing { } #[derive(Diagnostic)] -#[diag(const_eval_operator_non_const, code = E0015)] +#[diag(const_eval_non_const_operator, code = E0015)] pub struct NonConstOperator { #[primary_span] pub span: Span, pub kind: ConstContext, #[subdiagnostic] pub sugg: Option, + pub non: &'static str, } #[derive(Diagnostic)] -#[diag(const_eval_deref_coercion_non_const, code = E0015)] +#[diag(const_eval_non_const_deref_coercion, code = E0015)] #[note] pub struct NonConstDerefCoercion<'tcx> { #[primary_span] @@ -401,6 +411,7 @@ pub struct NonConstDerefCoercion<'tcx> { pub target_ty: Ty<'tcx>, #[note(const_eval_target_note)] pub deref_target: Option, + pub non: &'static str, } #[derive(Diagnostic)] From 147ac7ad5dd30a68a23e7abc23abe5691b7897b9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:19:30 +0000 Subject: [PATCH 150/189] Couple of cleanups to num.rs --- src/num.rs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/num.rs b/src/num.rs index 0b7273d42b7e9..f44e2459a784d 100644 --- a/src/num.rs +++ b/src/num.rs @@ -2,10 +2,10 @@ use crate::prelude::*; -pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option { +pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC { use BinOp::*; use IntCC::*; - Some(match bin_op { + match bin_op { Eq => Equal, Lt => { if signed { @@ -36,8 +36,8 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option { UnsignedGreaterThan } } - _ => return None, - }) + _ => unreachable!(), + } } fn codegen_three_way_compare<'tcx>( @@ -48,8 +48,8 @@ fn codegen_three_way_compare<'tcx>( ) -> CValue<'tcx> { // This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per // - let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap(); - let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap(); + let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed); + let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed); let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs); let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs); let val = fx.bcx.ins().isub(gt, lt); @@ -63,11 +63,7 @@ fn codegen_compare_bin_op<'tcx>( lhs: Value, rhs: Value, ) -> CValue<'tcx> { - if bin_op == BinOp::Cmp { - return codegen_three_way_compare(fx, signed, lhs, rhs); - } - - let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap(); + let intcc = crate::num::bin_op_to_intcc(bin_op, signed); let val = fx.bcx.ins().icmp(intcc, lhs, rhs); CValue::by_val(val, fx.layout_of(fx.tcx.types.bool)) } @@ -79,7 +75,7 @@ pub(crate) fn codegen_binop<'tcx>( in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { match bin_op { - BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => { + BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { match in_lhs.layout().ty.kind() { ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => { let signed = type_sign(in_lhs.layout().ty); @@ -91,6 +87,16 @@ pub(crate) fn codegen_binop<'tcx>( _ => {} } } + BinOp::Cmp => match in_lhs.layout().ty.kind() { + ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => { + let signed = type_sign(in_lhs.layout().ty); + let lhs = in_lhs.load_scalar(fx); + let rhs = in_rhs.load_scalar(fx); + + return codegen_three_way_compare(fx, signed, lhs, rhs); + } + _ => {} + }, _ => {} } @@ -357,14 +363,12 @@ pub(crate) fn codegen_float_binop<'tcx>( _ => bug!(), }; - let ret_val = fx.lib_call( + fx.lib_call( name, vec![AbiParam::new(ty), AbiParam::new(ty)], vec![AbiParam::new(ty)], &[lhs, rhs], - )[0]; - - return CValue::by_val(ret_val, in_lhs.layout()); + )[0] } BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { let fltcc = match bin_op { @@ -431,13 +435,9 @@ pub(crate) fn codegen_ptr_binop<'tcx>( BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => { let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr); - let ptr_cmp = - fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr); - let extra_cmp = fx.bcx.ins().icmp( - bin_op_to_intcc(bin_op, false).unwrap(), - lhs_extra, - rhs_extra, - ); + let ptr_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false), lhs_ptr, rhs_ptr); + let extra_cmp = + fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false), lhs_extra, rhs_extra); fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp) } From 924000d70ebb5f0de849447fd21127e34f8a8ba1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Dec 2024 21:53:07 +0000 Subject: [PATCH 151/189] Unify conditional and non const call error reporting --- compiler/rustc_const_eval/messages.ftl | 14 +- .../src/check_consts/check.rs | 14 +- .../rustc_const_eval/src/check_consts/ops.rs | 431 ++++++++++-------- compiler/rustc_const_eval/src/errors.rs | 32 +- tests/ui/issues/issue-25901.rs | 2 +- tests/ui/issues/issue-25901.stderr | 10 +- ...bitrary-self-from-method-substs-ice.stderr | 2 +- .../const-traits/cross-crate.stock.stderr | 6 +- .../const-traits/cross-crate.stocknc.stderr | 12 +- .../const-traits/staged-api-user-crate.stderr | 2 +- .../super-traits-fail-3.nyn.stderr | 6 +- .../super-traits-fail-3.nyy.stderr | 6 +- 12 files changed, 288 insertions(+), 249 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 7c66f5dedb5bc..4861b7a4430f0 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -21,8 +21,6 @@ const_eval_closure_call = closures need an RFC before allowed to be called in {const_eval_const_context}s const_eval_closure_fndef_not_const = function defined here, but it is not `const` -const_eval_conditionally_const_call = - cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s const_eval_consider_dereferencing = consider dereferencing here @@ -239,18 +237,18 @@ const_eval_non_const_await = cannot convert `{$ty}` into a future in {const_eval_const_context}s const_eval_non_const_closure = - cannot call {$non}-const closure in {const_eval_const_context}s + cannot call {$non_or_conditionally}-const closure in {const_eval_const_context}s const_eval_non_const_deref_coercion = - cannot perform {$non}-const deref coercion on `{$ty}` in {const_eval_const_context}s + cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {const_eval_const_context}s .note = attempting to deref into `{$target_ty}` .target_note = deref defined here const_eval_non_const_fmt_macro_call = - cannot call {$non}-const formatting macro in {const_eval_const_context}s + cannot call {$non_or_conditionally}-const formatting macro in {const_eval_const_context}s const_eval_non_const_fn_call = - cannot call {$non}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s + cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s const_eval_non_const_for_loop_into_iter = cannot use `for` loop on `{$ty}` in {const_eval_const_context}s @@ -259,13 +257,13 @@ const_eval_non_const_impl = impl defined here, but it is not `const` const_eval_non_const_intrinsic = - cannot call {$non}-const intrinsic `{$name}` in {const_eval_const_context}s + cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s const_eval_non_const_match_eq = cannot match on `{$ty}` in {const_eval_const_context}s .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es const_eval_non_const_operator = - cannot call {$non}-const operator in {const_eval_const_context}s + cannot call {$non_or_conditionally}-const operator in {const_eval_const_context}s const_eval_non_const_question_branch = `?` is not allowed on `{$ty}` in {const_eval_const_context}s diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index e895c44199b81..015e16716821a 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -708,7 +708,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if trait_is_const { // Trait calls are always conditionally-const. - self.check_op(ops::ConditionallyConstCall { callee, args: fn_args }); + self.check_op(ops::ConditionallyConstCall { + callee, + args: fn_args, + span: *fn_span, + call_source, + }); // FIXME(const_trait_impl): do a more fine-grained check whether this // particular trait can be const-stably called. } else { @@ -726,7 +731,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Even if we know the callee, ensure we can use conditionally-const calls. if has_const_conditions { - self.check_op(ops::ConditionallyConstCall { callee, args: fn_args }); + self.check_op(ops::ConditionallyConstCall { + callee, + args: fn_args, + span: *fn_span, + call_source, + }); } // At this point, we are calling a function, `callee`, whose `DefId` is known... diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 5aa0de9ce8655..6707ebe7d1c84 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{ suggest_constraining_type_param, }; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; +use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use rustc_trait_selection::traits::SelectionContext; use tracing::debug; @@ -77,6 +78,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { pub(crate) struct ConditionallyConstCall<'tcx> { pub callee: DefId, pub args: GenericArgsRef<'tcx>, + pub span: Span, + pub call_source: CallSource, } impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { @@ -91,24 +94,22 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let mut err = ccx.tcx.sess.create_feature_err( - errors::ConditionallyConstCall { - span, - def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args), - def_descr: ccx.tcx.def_descr(self.callee), - kind: ccx.const_kind(), - }, - sym::const_trait_impl, + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { + let mut diag = build_error_for_const_call( + ccx, + self.callee, + self.args, + self.span, + self.call_source, + "conditionally", + |_, _, _| {}, ); - err.note(format!( - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - )); + // Override code and mention feature. + diag.code(E0658); + add_feature_diagnostics(&mut diag, ccx.tcx.sess, sym::const_trait_impl); - err + diag } } @@ -126,216 +127,250 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { - let FnCallNonConst { callee, args, span, call_source } = *self; - let ConstCx { tcx, typing_env, .. } = *ccx; + let tcx = ccx.tcx; let caller = ccx.def_id(); - let note_trait_if_possible = |err, self_ty: Ty<'_>, trait_id| { - let trait_ref = TraitRef::from_method(tcx, trait_id, args); - - match self_ty.kind() { - Param(param_ty) => { - debug!(?param_ty); - if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { - let constraint = with_no_trimmed_paths!(format!( - "~const {}", - trait_ref.print_trait_sugared(), - )); - suggest_constraining_type_param( - tcx, - generics, - err, - param_ty.name.as_str(), - &constraint, - Some(trait_ref.def_id), - None, - ); + let mut err = build_error_for_const_call( + ccx, + self.callee, + self.args, + self.span, + self.call_source, + "non", + |err, self_ty, trait_id| { + // FIXME(const_trait_impl): Do we need any of this on the non-const codepath? + + let trait_ref = TraitRef::from_method(tcx, trait_id, self.args); + + match self_ty.kind() { + Param(param_ty) => { + debug!(?param_ty); + if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { + let constraint = with_no_trimmed_paths!(format!( + "~const {}", + trait_ref.print_trait_sugared(), + )); + suggest_constraining_type_param( + tcx, + generics, + err, + param_ty.name.as_str(), + &constraint, + Some(trait_ref.def_id), + None, + ); + } } - } - ty::Adt(..) => { - let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let obligation = - Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - let mut selcx = SelectionContext::new(&infcx); - let implsrc = selcx.select(&obligation); - if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { - // FIXME(const_trait_impl) revisit this - if !tcx.is_const_trait_impl(data.impl_def_id) { - let span = tcx.def_span(data.impl_def_id); - err.subdiagnostic(errors::NonConstImplNote { span }); + ty::Adt(..) => { + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ccx.typing_env); + let obligation = + Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); + let mut selcx = SelectionContext::new(&infcx); + let implsrc = selcx.select(&obligation); + if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { + // FIXME(const_trait_impl) revisit this + if !tcx.is_const_trait_impl(data.impl_def_id) { + let span = tcx.def_span(data.impl_def_id); + err.subdiagnostic(errors::NonConstImplNote { span }); + } } } + _ => {} } - _ => {} + }, + ); + + if let ConstContext::Static(_) = ccx.const_kind() { + err.note(fluent_generated::const_eval_lazy_lock); + } + + err + } +} + +/// Build an error message reporting that a function call is not const (or only +/// conditionally const). In case that this call is desugared (like an operator +/// or sugar from something like a `for` loop), try to build a better error message +/// that doesn't call it a method. +fn build_error_for_const_call<'tcx>( + ccx: &ConstCx<'_, 'tcx>, + callee: DefId, + args: ty::GenericArgsRef<'tcx>, + span: Span, + call_source: CallSource, + non_or_conditionally: &'static str, + note_trait_if_possible: impl FnOnce(&mut Diag<'tcx>, Ty<'tcx>, DefId), +) -> Diag<'tcx> { + let tcx = ccx.tcx; + + let call_kind = + call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None); + + debug!(?call_kind); + + let mut err = match call_kind { + CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { + macro_rules! error { + ($err:ident) => { + tcx.dcx().create_err(errors::$err { + span, + ty: self_ty, + kind: ccx.const_kind(), + non_or_conditionally, + }) + }; } - }; - - let call_kind = - call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None); - - debug!(?call_kind); - - let mut err = match call_kind { - CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { - macro_rules! error { - ($err:ident) => { - tcx.dcx().create_err(errors::$err { - span, - ty: self_ty, - kind: ccx.const_kind(), - non: "non", - }) - }; - } - // Don't point at the trait if this is a desugaring... - // FIXME(const_trait_impl): we could perhaps do this for `Iterator`. - match kind { - CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => { - error!(NonConstForLoopIntoIter) - } - CallDesugaringKind::QuestionBranch => { - error!(NonConstQuestionBranch) - } - CallDesugaringKind::QuestionFromResidual => { - error!(NonConstQuestionFromResidual) - } - CallDesugaringKind::TryBlockFromOutput => { - error!(NonConstTryBlockFromOutput) - } - CallDesugaringKind::Await => { - error!(NonConstAwait) - } + // Don't point at the trait if this is a desugaring... + // FIXME(const_trait_impl): we could perhaps do this for `Iterator`. + match kind { + CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => { + error!(NonConstForLoopIntoIter) + } + CallDesugaringKind::QuestionBranch => { + error!(NonConstQuestionBranch) + } + CallDesugaringKind::QuestionFromResidual => { + error!(NonConstQuestionFromResidual) + } + CallDesugaringKind::TryBlockFromOutput => { + error!(NonConstTryBlockFromOutput) + } + CallDesugaringKind::Await => { + error!(NonConstAwait) } } - CallKind::FnCall { fn_trait_id, self_ty } => { - let note = match self_ty.kind() { - FnDef(def_id, ..) => { - let span = tcx.def_span(*def_id); - if ccx.tcx.is_const_fn(*def_id) { - span_bug!(span, "calling const FnDef errored when it shouldn't"); - } - - Some(errors::NonConstClosureNote::FnDef { span }) + } + CallKind::FnCall { fn_trait_id, self_ty } => { + let note = match self_ty.kind() { + FnDef(def_id, ..) => { + let span = tcx.def_span(*def_id); + if ccx.tcx.is_const_fn(*def_id) { + span_bug!(span, "calling const FnDef errored when it shouldn't"); } - FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr), - Closure(..) => Some(errors::NonConstClosureNote::Closure), - _ => None, - }; - let mut err = tcx.dcx().create_err(errors::NonConstClosure { + Some(errors::NonConstClosureNote::FnDef { span }) + } + FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr), + Closure(..) => Some(errors::NonConstClosureNote::Closure), + _ => None, + }; + + let mut err = tcx.dcx().create_err(errors::NonConstClosure { + span, + kind: ccx.const_kind(), + note, + non_or_conditionally, + }); + + note_trait_if_possible(&mut err, self_ty, fn_trait_id); + err + } + CallKind::Operator { trait_id, self_ty, .. } => { + let mut err = if let CallSource::MatchCmp = call_source { + tcx.dcx().create_err(errors::NonConstMatchEq { span, kind: ccx.const_kind(), - note, - non: "non", - }); - - note_trait_if_possible(&mut err, self_ty, fn_trait_id); - err - } - CallKind::Operator { trait_id, self_ty, .. } => { - let mut err = if let CallSource::MatchCmp = call_source { - tcx.dcx().create_err(errors::NonConstMatchEq { - span, - kind: ccx.const_kind(), - ty: self_ty, - non: "non", - }) - } else { - let mut sugg = None; - - 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 - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = *inner_ty; - } - let deref = "*".repeat(num_refs); - - if let Ok(call_str) = - ccx.tcx.sess.source_map().span_to_snippet(span) - { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = call_str[(eq_idx + 2)..] - .find(|c: char| !c.is_whitespace()) - { - let rhs_pos = span.lo() - + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - sugg = Some(errors::ConsiderDereferencing { - deref, - span: span.shrink_to_lo(), - rhs_span, - }); - } + ty: self_ty, + non_or_conditionally, + }) + } else { + let mut sugg = None; + + 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 + && self_ty.is_ref() + && self_ty.peel_refs().is_primitive() => + { + let mut num_refs = 0; + let mut tmp_ty = self_ty; + while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { + num_refs += 1; + tmp_ty = *inner_ty; + } + let deref = "*".repeat(num_refs); + + if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) { + if let Some(eq_idx) = call_str.find("==") { + if let Some(rhs_idx) = + call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace()) + { + let rhs_pos = + span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx); + let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); + sugg = Some(errors::ConsiderDereferencing { + deref, + span: span.shrink_to_lo(), + rhs_span, + }); } } } - _ => {} } + _ => {} } - tcx.dcx().create_err(errors::NonConstOperator { - span, - kind: ccx.const_kind(), - sugg, - non: "non", - }) - }; - - note_trait_if_possible(&mut err, self_ty, trait_id); - err - } - CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { - // Check first whether the source is accessible (issue #87060) - let target = if tcx.sess.source_map().is_span_accessible(deref_target) { - Some(deref_target) - } else { - None - }; - - let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion { + } + tcx.dcx().create_err(errors::NonConstOperator { span, - ty: self_ty, kind: ccx.const_kind(), - target_ty: deref_target_ty, - deref_target: target, - non: "non", - }); + sugg, + non_or_conditionally, + }) + }; - note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); - err - } - _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { - ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind(), non: "non" }) - } - _ => ccx.dcx().create_err(errors::NonConstFnCall { + note_trait_if_possible(&mut err, self_ty, trait_id); + err + } + CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { + // Check first whether the source is accessible (issue #87060) + let target = if tcx.sess.source_map().is_span_accessible(deref_target) { + Some(deref_target) + } else { + None + }; + + let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion { span, - def_descr: ccx.tcx.def_descr(callee), - def_path_str: ccx.tcx.def_path_str_with_args(callee, args), + ty: self_ty, kind: ccx.const_kind(), - non: "non", - }), - }; + target_ty: deref_target_ty, + deref_target: target, + non_or_conditionally, + }); + + note_trait_if_possible( + &mut err, + self_ty, + tcx.require_lang_item(LangItem::Deref, Some(span)), + ); + err + } + _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { + ccx.dcx().create_err(errors::NonConstFmtMacroCall { + span, + kind: ccx.const_kind(), + non_or_conditionally, + }) + } + _ => ccx.dcx().create_err(errors::NonConstFnCall { + span, + def_descr: ccx.tcx.def_descr(callee), + def_path_str: ccx.tcx.def_path_str_with_args(callee, args), + kind: ccx.const_kind(), + non_or_conditionally, + }), + }; - err.note(format!( - "calls in {}s are limited to constant functions, \ + err.note(format!( + "calls in {}s are limited to constant functions, \ tuple structs and tuple variants", - ccx.const_kind(), - )); - - if let ConstContext::Static(_) = ccx.const_kind() { - err.note(fluent_generated::const_eval_lazy_lock); - } + ccx.const_kind(), + )); - err - } + err } /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 8e105f9beec96..3fe78171cd944 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -174,17 +174,7 @@ pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, pub kind: ConstContext, - pub non: &'static str, -} - -#[derive(Diagnostic)] -#[diag(const_eval_conditionally_const_call)] -pub(crate) struct ConditionallyConstCall { - #[primary_span] - pub span: Span, - pub def_path_str: String, - pub def_descr: &'static str, - pub kind: ConstContext, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -195,7 +185,7 @@ pub(crate) struct NonConstFnCall { pub def_path_str: String, pub def_descr: &'static str, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -302,7 +292,7 @@ pub struct NonConstMatchEq<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -312,7 +302,7 @@ pub struct NonConstForLoopIntoIter<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -322,7 +312,7 @@ pub struct NonConstQuestionBranch<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -332,7 +322,7 @@ pub struct NonConstQuestionFromResidual<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -342,7 +332,7 @@ pub struct NonConstTryBlockFromOutput<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -352,7 +342,7 @@ pub struct NonConstAwait<'tcx> { pub span: Span, pub ty: Ty<'tcx>, pub kind: ConstContext, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -363,7 +353,7 @@ pub struct NonConstClosure { pub kind: ConstContext, #[subdiagnostic] pub note: Option, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Subdiagnostic)] @@ -397,7 +387,7 @@ pub struct NonConstOperator { pub kind: ConstContext, #[subdiagnostic] pub sugg: Option, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] @@ -411,7 +401,7 @@ pub struct NonConstDerefCoercion<'tcx> { pub target_ty: Ty<'tcx>, #[note(const_eval_target_note)] pub deref_target: Option, - pub non: &'static str, + pub non_or_conditionally: &'static str, } #[derive(Diagnostic)] diff --git a/tests/ui/issues/issue-25901.rs b/tests/ui/issues/issue-25901.rs index eae038c71a0ea..bfcee1ac503a2 100644 --- a/tests/ui/issues/issue-25901.rs +++ b/tests/ui/issues/issue-25901.rs @@ -2,7 +2,7 @@ struct A; struct B; static S: &'static B = &A; -//~^ ERROR cannot call conditionally-const method +//~^ ERROR cannot perform conditionally-const deref coercion use std::ops::Deref; diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr index b100ce30a41b2..a954f38af8397 100644 --- a/tests/ui/issues/issue-25901.stderr +++ b/tests/ui/issues/issue-25901.stderr @@ -1,13 +1,19 @@ -error[E0658]: cannot call conditionally-const method `::deref` in statics +error[E0658]: cannot perform conditionally-const deref coercion on `A` in statics --> $DIR/issue-25901.rs:4:24 | LL | static S: &'static B = &A; | ^^ | + = note: attempting to deref into `B` +note: deref defined here + --> $DIR/issue-25901.rs:10:5 + | +LL | type Target = B; + | ^^^^^^^^^^^ + = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in statics are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index 5ed82eb764901..90b63249eca1a 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -4,10 +4,10 @@ error[E0658]: cannot call conditionally-const method `::deref` in co LL | self.0 | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0493]: destructor of `R` cannot be evaluated at compile-time --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43 diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr index de73d904f42bf..7cdde5a079f2d 100644 --- a/tests/ui/traits/const-traits/cross-crate.stock.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr @@ -1,13 +1,13 @@ error[E0658]: cannot call conditionally-const method `::func` in constant functions - --> $DIR/cross-crate.rs:22:5 + --> $DIR/cross-crate.rs:22:11 | LL | Const.func(); - | ^^^^^^^^^^^^ + | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr index 74fa35cfd04d4..2358731c901f6 100644 --- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr @@ -1,24 +1,24 @@ error[E0658]: cannot call conditionally-const method `::func` in constant functions - --> $DIR/cross-crate.rs:19:5 + --> $DIR/cross-crate.rs:19:14 | LL | NonConst.func(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0658]: cannot call conditionally-const method `::func` in constant functions - --> $DIR/cross-crate.rs:22:5 + --> $DIR/cross-crate.rs:22:11 | LL | Const.func(); - | ^^^^^^^^^^^^ + | ^^^^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index 970e0c1252cfb..400c76fcaf494 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -4,10 +4,10 @@ error[E0658]: cannot call conditionally-const associated function ` for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr index 1b1ca4b28a462..024db4b6d68d0 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr @@ -39,15 +39,15 @@ LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: cannot call conditionally-const method `::a` in constant functions - --> $DIR/super-traits-fail-3.rs:36:5 + --> $DIR/super-traits-fail-3.rs:36:7 | LL | x.a(); - | ^^^^^ + | ^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 5 previous errors diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr index 1b1ca4b28a462..024db4b6d68d0 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr @@ -39,15 +39,15 @@ LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: cannot call conditionally-const method `::a` in constant functions - --> $DIR/super-traits-fail-3.rs:36:5 + --> $DIR/super-traits-fail-3.rs:36:7 | LL | x.a(); - | ^^^^^ + | ^^^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 5 previous errors From bb4a2599082c2666470c4e53f14bd536d4fcd62f Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 9 Jan 2025 18:01:20 +0100 Subject: [PATCH 152/189] Bump nightly version -> 2024-01-09 --- clippy_utils/README.md | 2 +- rust-toolchain | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 73fefbcd5705c..c267b804124af 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2024-12-26 +nightly-2025-01-09 ``` diff --git a/rust-toolchain b/rust-toolchain index 1000d90f52a52..b1f0a82b1f475 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2024-12-26" +channel = "nightly-2025-01-09" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 663892bea721cc6eb6364556ce4c2e1da19007aa Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 9 Jan 2025 18:01:44 +0100 Subject: [PATCH 153/189] Bump Clippy version -> 0.1.86 --- Cargo.toml | 2 +- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bb259c77ee375..e9b11d5df2f29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy" # begin autogenerated version -version = "0.1.85" +version = "0.1.86" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 3f18a0bc7d253..c761e207c6b61 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_config" # begin autogenerated version -version = "0.1.85" +version = "0.1.86" # end autogenerated version edition = "2021" publish = false diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index c1f8e82f69884..b575ac1bf4cc5 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin autogenerated version -version = "0.1.85" +version = "0.1.86" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 945827c98c179..7fa070cd226be 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_utils" # begin autogenerated version -version = "0.1.85" +version = "0.1.86" # end autogenerated version edition = "2021" description = "Helpful tools for writing lints, provided as they are used in Clippy" From 00448ab45ab952749d4d4d14894cee8ff3231cd3 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 9 Jan 2025 17:32:29 +0000 Subject: [PATCH 154/189] Make bare-fn test less dependent on path width --- .../fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs | 2 ++ .../fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs index cf73fd8d31fbb..f776a6ce4c12f 100644 --- a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs +++ b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs @@ -1,3 +1,5 @@ +// Sets some arbitrarily large width for more consistent output (see #135288). +//@ compile-flags: --diagnostic-width=120 struct Argument; struct Return; diff --git a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr index 5b89158b0dba2..ba0af763975d4 100644 --- a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr +++ b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied - --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:12:11 + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11 | LL | takes(function); | ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}` @@ -7,7 +7,7 @@ LL | takes(function); | required by a bound introduced by this call | note: required by a bound in `takes` - --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18 + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:11:18 | LL | fn takes(_: impl Trait) {} | ^^^^^ required by this bound in `takes` @@ -16,18 +16,18 @@ help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`, LL | takes(function as fn(Argument) -> Return); | +++++++++++++++++++++++++ -error[E0277]: the trait bound `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}: Trait` is not satisfied - --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11 +error[E0277]: the trait bound `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:16:11: 16:34}: Trait` is not satisfied + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:16:11 | LL | takes(|_: Argument| -> Return { todo!() }); | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | - = help: the trait `Trait` is not implemented for closure `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}` + = help: the trait `Trait` is not implemented for closure `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:16:11: 16:34}` = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return` note: required by a bound in `takes` - --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18 + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:11:18 | LL | fn takes(_: impl Trait) {} | ^^^^^ required by this bound in `takes` From 8795750d43e650e35246e590538c73a4f18818cd Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Mon, 4 Nov 2024 20:59:22 +0300 Subject: [PATCH 155/189] Used pthread name functions returning result for FreeBSD and DragonFly --- library/std/src/sys/pal/unix/thread.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 040246618360f..692fc845b1d68 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -129,25 +129,27 @@ impl Thread { } } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"))] pub fn set_name(name: &CStr) { - const TASK_COMM_LEN: usize = 16; - unsafe { - // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. - let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + // Linux limits the allowed length of the name. + const TASK_COMM_LEN: usize = 16; + let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + } else { + // FreeBSD and DragonFly BSD do not enforce length limits. + } + }; + // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux, + // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0. let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. debug_assert_eq!(res, 0); } } - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "nuttx" - ))] + #[cfg(any(target_os = "openbsd", target_os = "nuttx"))] pub fn set_name(name: &CStr) { unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); From 43c3b30d3773d6061a91cd131fc4a48ad1a38f6a Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 9 Jan 2025 19:33:06 +0100 Subject: [PATCH 156/189] Update Cargo.lock --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26971e8a120d6..0cab392454e5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,7 +541,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clippy" -version = "0.1.85" +version = "0.1.86" dependencies = [ "anstream", "cargo_metadata 0.18.1", @@ -572,7 +572,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.85" +version = "0.1.86" dependencies = [ "clippy_utils", "itertools", @@ -597,7 +597,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.85" +version = "0.1.86" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -620,7 +620,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.85" +version = "0.1.86" dependencies = [ "arrayvec", "itertools", From c8b29d6f6f9a7953e41fc71a6a7c6762cf489c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 9 Jan 2025 21:40:29 +0100 Subject: [PATCH 157/189] CI: fix name of jobs There is a difference between the `image` (the Dockerfile), the `name` of the job (which determines also its properties) and the `full_name`, which includes the `auto/try/pr` prefix. --- .github/workflows/ci.yml | 6 +++--- src/ci/github-actions/ci.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8d7560ffcf41..c650df6a0ec2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: run: python3 src/ci/github-actions/ci.py calculate-job-matrix >> $GITHUB_OUTPUT id: jobs job: - name: ${{ matrix.name }} + name: ${{ matrix.full_name }} needs: [ calculate_matrix ] runs-on: "${{ matrix.os }}" defaults: @@ -67,7 +67,7 @@ jobs: shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }} timeout-minutes: 360 env: - CI_JOB_NAME: ${{ matrix.image }} + CI_JOB_NAME: ${{ matrix.name }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} @@ -233,7 +233,7 @@ jobs: env: DATADOG_SITE: datadoghq.com DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }} - DD_GITHUB_JOB_NAME: ${{ matrix.name }} + DD_GITHUB_JOB_NAME: ${{ matrix.full_name }} run: | cd src/ci npm ci diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py index 97539cf1cdb24..b7dac412dbecf 100755 --- a/src/ci/github-actions/ci.py +++ b/src/ci/github-actions/ci.py @@ -37,7 +37,7 @@ def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]: # Create a copy of the `job` dictionary to avoid modifying `jobs` new_job = dict(job) new_job["image"] = get_job_image(new_job) - new_job["name"] = f"{prefix} - {new_job['name']}" + new_job["full_name"] = f"{prefix} - {new_job['name']}" modified_jobs.append(new_job) return modified_jobs From 5e505189cd2b5355eb4b24bdce7aca7ca4e65189 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Thu, 9 Jan 2025 21:25:59 +0100 Subject: [PATCH 158/189] Add tests cases from review of #132289 --- .../auxiliary/pr_review_132289_2_lib.rs | 37 +++++++++++++ .../auxiliary/pr_review_132289_3_lib.rs | 12 +++++ tests/ui/coherence/pr-review-132289-1.rs | 52 +++++++++++++++++++ tests/ui/coherence/pr-review-132289-2.rs | 26 ++++++++++ tests/ui/coherence/pr-review-132289-3.rs | 50 ++++++++++++++++++ .../coherence/pr-review-132289-3.run.stdout | 1 + 6 files changed, 178 insertions(+) create mode 100644 tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs create mode 100644 tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs create mode 100644 tests/ui/coherence/pr-review-132289-1.rs create mode 100644 tests/ui/coherence/pr-review-132289-2.rs create mode 100644 tests/ui/coherence/pr-review-132289-3.rs create mode 100644 tests/ui/coherence/pr-review-132289-3.run.stdout diff --git a/tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs b/tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs new file mode 100644 index 0000000000000..4b79147dce109 --- /dev/null +++ b/tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs @@ -0,0 +1,37 @@ +pub type A = &'static [usize; 1]; +pub type B = &'static [usize; 100]; + +pub trait Trait

{ + type Assoc; +} + +pub type Dyn

= dyn Trait; + +pub trait LocallyUnimplemented

{} + +impl Trait

for T +where + T: LocallyUnimplemented

, +{ + type Assoc = B; +} + +trait MakeArray { + fn make() -> &'static Arr; +} +impl MakeArray<[usize; N]> for () { + fn make() -> &'static [usize; N] { + &[1337; N] + } +} + +// it would be sound for this return type to be interpreted as being +// either of A or B, if that's what a soundness fix for overlap of +// dyn Trait's impls would entail + +// In this test, we check at the call-site that the interpretation +// is consistent across crates in this specific scenario. +pub fn function

() -> ( as Trait

>::Assoc, usize) { + let val = <() as MakeArray<_>>::make(); + (val, val.len()) +} diff --git a/tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs b/tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs new file mode 100644 index 0000000000000..f90be3b2487e5 --- /dev/null +++ b/tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs @@ -0,0 +1,12 @@ +use std::ops::Index; + +pub trait Trait { + fn f(&self) + where + dyn Index<(), Output = ()>: Index<()>; + // rustc (correctly) determines ^^^^^^^^ this bound to be true +} + +pub fn call(x: &dyn Trait) { + x.f(); // so we can call `f` +} diff --git a/tests/ui/coherence/pr-review-132289-1.rs b/tests/ui/coherence/pr-review-132289-1.rs new file mode 100644 index 0000000000000..ab3ed9655e071 --- /dev/null +++ b/tests/ui/coherence/pr-review-132289-1.rs @@ -0,0 +1,52 @@ +// This is a regression test for issues that came up during review of the (closed) +// PR #132289; this single-crate test case is +// the first example from @steffahn during review. +// https://github.com/rust-lang/rust/pull/132289#issuecomment-2564492153 + +//@ check-pass + +type A = &'static [usize; 1]; +type B = &'static [usize; 100]; + +type DynSomething = dyn Something; + +trait Super { + type Assoc; +} +impl Super for Foo { + type Assoc = A; +} + +trait IsDynSomething {} +impl IsDynSomething for DynSomething {} + +impl Super for T +where + T: IsDynSomething, +{ + type Assoc = B; +} + +trait Something: Super { + fn method(&self) -> Self::Assoc; +} + +struct Foo; +impl Something for Foo { + fn method(&self) -> Self::Assoc { + &[1337] + } +} + +fn main() { + let x = &Foo; + let y: &DynSomething = x; + + // no surprises here + let _arr1: A = x.method(); + + // this (`_arr2`) can't ever become B either, soundly + let _arr2: A = y.method(); + // there aren't any other arrays being defined anywhere in this + // test case, besides the length-1 one containing [1337] +} diff --git a/tests/ui/coherence/pr-review-132289-2.rs b/tests/ui/coherence/pr-review-132289-2.rs new file mode 100644 index 0000000000000..95ad86c61ff19 --- /dev/null +++ b/tests/ui/coherence/pr-review-132289-2.rs @@ -0,0 +1,26 @@ +// This is a regression test for issues that came up during review of the (closed) +// PR #132289; this 2-crate test case is adapted from +// the second example from @steffahn during review. +// https://github.com/rust-lang/rust/pull/132289#issuecomment-2564587796 + +//@ run-pass +//@ aux-build: pr_review_132289_2_lib.rs + +extern crate pr_review_132289_2_lib; + +use pr_review_132289_2_lib::{function, Dyn, LocallyUnimplemented}; + +struct Param; + +impl LocallyUnimplemented for Dyn {} + +// it would be sound for `function::`'s return type to be +// either of A or B, if that's what a soundness fix for overlap of +// dyn Trait's impls would entail + +// In this test, we check at this call-site that the interpretation +// is consistent with the function definition's body. +fn main() { + let (arr, len) = function::(); + assert_eq!(arr.len(), len); +} diff --git a/tests/ui/coherence/pr-review-132289-3.rs b/tests/ui/coherence/pr-review-132289-3.rs new file mode 100644 index 0000000000000..7e597baa6ec29 --- /dev/null +++ b/tests/ui/coherence/pr-review-132289-3.rs @@ -0,0 +1,50 @@ +// This is a regression test for issues that came up during review of the (closed) +// PR #132289; this 3-ish-crate (including std) test case is adapted from +// the third example from @steffahn during review. +// https://github.com/rust-lang/rust/pull/132289#issuecomment-2564599221 + +//@ run-pass +//@ check-run-results +//@ aux-build: pr_review_132289_3_lib.rs + +extern crate pr_review_132289_3_lib; + +use std::ops::Index; + +use pr_review_132289_3_lib::{call, Trait}; + +trait SubIndex: Index {} + +struct Param; + +trait Project { + type Ty: ?Sized; +} +impl Project for () { + type Ty = dyn SubIndex; +} + +impl Index for <() as Project>::Ty { + type Output = (); + + fn index(&self, _: Param) -> &() { + &() + } +} + +struct Struct; + +impl Trait for Struct { + fn f(&self) + where + // higher-ranked to allow potentially-false bounds + for<'a> dyn Index<(), Output = ()>: Index<()>, + // after #132289 rustc used to believe this bound false + { + println!("hello!"); + } +} + +fn main() { + call(&Struct); // <- would segfault if the method `f` wasn't part of the vtable +} diff --git a/tests/ui/coherence/pr-review-132289-3.run.stdout b/tests/ui/coherence/pr-review-132289-3.run.stdout new file mode 100644 index 0000000000000..4effa19f4f75f --- /dev/null +++ b/tests/ui/coherence/pr-review-132289-3.run.stdout @@ -0,0 +1 @@ +hello! From d52564118b2e3f7140e911dec4021decda6493e8 Mon Sep 17 00:00:00 2001 From: Asuna Date: Sun, 5 Jan 2025 23:47:32 +0100 Subject: [PATCH 159/189] Append `TokenTree` with `ToTokens` in `proc_macro::quote!` --- library/proc_macro/src/lib.rs | 2 +- library/proc_macro/src/quote.rs | 109 ++++++++++++++----------- tests/ui/proc-macro/quote-debug.stdout | 42 +++++----- 3 files changed, 87 insertions(+), 66 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 26a09f0daca02..b19c9cee75a0b 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -419,7 +419,7 @@ pub mod token_stream { /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. #[unstable(feature = "proc_macro_quote", issue = "54722")] -#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)] +#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals, proc_macro_totokens)] #[rustc_builtin_macro] pub macro quote($($t:tt)*) { /* compiler built-in */ diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs index 6faa41b297005..27c8458a351ca 100644 --- a/library/proc_macro/src/quote.rs +++ b/library/proc_macro/src/quote.rs @@ -4,7 +4,9 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use crate::{ + Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree, +}; macro_rules! minimal_quote_tt { (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) }; @@ -24,16 +26,15 @@ macro_rules! minimal_quote_tt { macro_rules! minimal_quote_ts { ((@ $($t:tt)*)) => { $($t)* }; (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() + { + let mut c = ( + TokenTree::from(Punct::new(':', Spacing::Joint)), + TokenTree::from(Punct::new(':', Spacing::Alone)) + ); + c.0.set_span(Span::def_site()); + c.1.set_span(Span::def_site()); + [c.0, c.1].into_iter().collect::() + } }; ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) }; } @@ -47,11 +48,13 @@ macro_rules! minimal_quote_ts { /// Note: supported tokens are a subset of the real `quote!`, but /// unquoting is different: instead of `$x`, this uses `(@ expr)`. macro_rules! minimal_quote { - () => { TokenStream::new() }; ($($t:tt)*) => { - [ - $(TokenStream::from(minimal_quote_ts!($t)),)* - ].iter().cloned().collect::() + { + #[allow(unused_mut)] // In case the expansion is empty + let mut ts = TokenStream::new(); + $(ToTokens::to_tokens(&minimal_quote_ts!($t), &mut ts);)* + ts + } }; } @@ -66,35 +69,39 @@ pub fn quote(stream: TokenStream) -> TokenStream { } let proc_macro_crate = minimal_quote!(crate); let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(minimal_quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; + + let mut tokens = crate::TokenStream::new(); + for tree in stream { + if after_dollar { + after_dollar = false; + match tree { + TokenTree::Ident(_) => { + minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);) + .to_tokens(&mut tokens); + continue; } + TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} + _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), } + } else if let TokenTree::Punct(ref tt) = tree { + if tt.as_char() == '$' { + after_dollar = true; + continue; + } + } - Some(minimal_quote!(crate::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => minimal_quote!(crate::TokenTree::Punct(crate::Punct::new( + match tree { + TokenTree::Punct(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new( (@ TokenTree::from(Literal::character(tt.as_char()))), (@ match tt.spacing() { Spacing::Alone => minimal_quote!(crate::Spacing::Alone), Spacing::Joint => minimal_quote!(crate::Spacing::Joint), }), - ))), - TokenTree::Group(tt) => minimal_quote!(crate::TokenTree::Group(crate::Group::new( + )), &mut ts);) + } + TokenTree::Group(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Group(crate::Group::new( (@ match tt.delimiter() { Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis), Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace), @@ -102,12 +109,16 @@ pub fn quote(stream: TokenStream) -> TokenStream { Delimiter::None => minimal_quote!(crate::Delimiter::None), }), (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => minimal_quote!(crate::TokenTree::Ident(crate::Ident::new( + )), &mut ts);) + } + TokenTree::Ident(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new( (@ TokenTree::from(Literal::string(&tt.to_string()))), (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => minimal_quote!(crate::TokenTree::Literal({ + )), &mut ts);) + } + TokenTree::Literal(tt) => { + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) .parse::() .unwrap() @@ -120,16 +131,22 @@ pub fn quote(stream: TokenStream) -> TokenStream { } else { unreachable!() } - })) - })),)) - }) - .collect::(); - + }), &mut ts);) + } + } + .to_tokens(&mut tokens); + } if after_dollar { panic!("unexpected trailing `$` in `quote!`"); } - minimal_quote!([(@ tokens)].iter().cloned().collect::()) + minimal_quote! { + { + let mut ts = crate::TokenStream::new(); + (@ tokens) + ts + } + } } /// Quote a `Span` into a `TokenStream`. diff --git a/tests/ui/proc-macro/quote-debug.stdout b/tests/ui/proc-macro/quote-debug.stdout index d84b4e051e872..583599ff97524 100644 --- a/tests/ui/proc-macro/quote-debug.stdout +++ b/tests/ui/proc-macro/quote-debug.stdout @@ -19,25 +19,29 @@ extern crate std; extern crate proc_macro; fn main() { - [crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let", - crate::Span::recover_proc_macro_span(0)))), - crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello", - crate::Span::recover_proc_macro_span(1)))), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('=', - crate::Spacing::Alone))), - crate::TokenStream::from(crate::TokenTree::Literal({ - let mut iter = - "\"world\"".parse::().unwrap().into_iter(); - if let (Some(crate::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) { - lit.set_span(crate::Span::recover_proc_macro_span(2)); - lit - } else { - ::core::panicking::panic("internal error: entered unreachable code") - } - })), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new(';', - crate::Spacing::Alone)))].iter().cloned().collect::() + { + let mut ts = crate::TokenStream::new(); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let", + crate::Span::recover_proc_macro_span(0))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("hello", + crate::Span::recover_proc_macro_span(1))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=', + crate::Spacing::Alone)), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ + let mut iter = + "\"world\"".parse::().unwrap().into_iter(); + if let (Some(crate::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) { + lit.set_span(crate::Span::recover_proc_macro_span(2)); + lit + } else { + ::core::panicking::panic("internal error: entered unreachable code") + } + }), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';', + crate::Spacing::Alone)), &mut ts); + ts + } } const _: () = { From e9063c36a95f032b2f504e30fa19b22bc88c2dcd Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 8 Jan 2025 23:36:09 +0100 Subject: [PATCH 160/189] Migrate basic tests for `proc_macro::quote!` from `quote` crate --- tests/ui/proc-macro/quote/auxiliary/basic.rs | 360 ++++++++++++++++++ tests/ui/proc-macro/quote/basic.rs | 8 + .../{quote-debug.rs => quote/debug.rs} | 0 .../debug.stdout} | 0 4 files changed, 368 insertions(+) create mode 100644 tests/ui/proc-macro/quote/auxiliary/basic.rs create mode 100644 tests/ui/proc-macro/quote/basic.rs rename tests/ui/proc-macro/{quote-debug.rs => quote/debug.rs} (100%) rename tests/ui/proc-macro/{quote-debug.stdout => quote/debug.stdout} (100%) diff --git a/tests/ui/proc-macro/quote/auxiliary/basic.rs b/tests/ui/proc-macro/quote/auxiliary/basic.rs new file mode 100644 index 0000000000000..67927e5f6a8a0 --- /dev/null +++ b/tests/ui/proc-macro/quote/auxiliary/basic.rs @@ -0,0 +1,360 @@ +#![feature(proc_macro_quote)] +#![feature(proc_macro_totokens)] + +extern crate proc_macro; + +use std::borrow::Cow; +use std::ffi::{CStr, CString}; + +use proc_macro::*; + +#[proc_macro] +pub fn run_tests(_: TokenStream) -> TokenStream { + test_quote_impl(); + test_substitution(); + test_advanced(); + test_integer(); + test_floating(); + test_char(); + test_str(); + test_string(); + test_c_str(); + test_c_string(); + test_interpolated_literal(); + test_ident(); + test_underscore(); + test_duplicate(); + test_empty_quote(); + test_box_str(); + test_cow(); + test_append_tokens(); + test_outer_line_comment(); + test_inner_line_comment(); + test_outer_block_comment(); + test_inner_block_comment(); + test_outer_attr(); + test_inner_attr(); + // test_quote_raw_id(); // FIXME: Fix it in a subsequent commit + + TokenStream::new() +} + +// Based on https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/tests/test.rs +// +// FIXME(quote): +// The following tests are removed because they are not supported yet in `proc_macro::quote!` +// +// - quote_spanned: +// - fn test_quote_spanned_impl +// - fn test_type_inference_for_span +// - format_ident: +// - fn test_format_ident +// - fn test_format_ident_strip_raw +// - repetition: +// - fn test_iter +// - fn test_array +// - fn test_fancy_repetition +// - fn test_nested_fancy_repetition +// - fn test_duplicate_name_repetition +// - fn test_duplicate_name_repetition_no_copy +// - fn test_btreeset_repetition +// - fn test_variable_name_conflict +// - fn test_nonrep_in_repetition +// - fn test_closure +// - fn test_star_after_repetition + +struct X; + +impl ToTokens for X { + fn to_tokens(&self, tokens: &mut TokenStream) { + Ident::new("X", Span::call_site()).to_tokens(tokens) + } +} + +fn test_quote_impl() { + let tokens = quote! { + impl<'a, T: ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } + } + }; + + let expected = r#"impl < 'a, T : ToTokens > ToTokens for & 'a T +{ + fn to_tokens(& self, tokens : & mut TokenStream) + { (** self).to_tokens(tokens) } +}"#; + + assert_eq!(expected, tokens.to_string()); +} + +fn test_substitution() { + let x = X; + let tokens = quote!($x <$x> ($x) [$x] {$x}); + + let expected = "X (X) [X] { X }"; + + assert_eq!(expected, tokens.to_string()); +} + +fn test_advanced() { + let generics = quote!( <'a, T> ); + + let where_clause = quote!( where T: Serialize ); + + let field_ty = quote!(String); + + let item_ty = quote!(Cow<'a, str>); + + let path = quote!(SomeTrait::serialize_with); + + let value = quote!(self.x); + + let tokens = quote! { + struct SerializeWith $generics $where_clause { + value: &'a $field_ty, + phantom: ::std::marker::PhantomData<$item_ty>, + } + + impl $generics ::serde::Serialize for SerializeWith $generics $where_clause { + fn serialize(&self, s: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer + { + $path(self.value, s) + } + } + + SerializeWith { + value: $value, + phantom: ::std::marker::PhantomData::<$item_ty>, + } + }; + + let expected = r#"struct SerializeWith < 'a, T > where T : Serialize +{ + value : & 'a String, phantom : :: std :: marker :: PhantomData >, +} impl < 'a, T > :: serde :: Serialize for SerializeWith < 'a, T > where T : +Serialize +{ + fn serialize < S > (& self, s : & mut S) -> Result < (), S :: Error > + where S : :: serde :: Serializer + { SomeTrait :: serialize_with(self.value, s) } +} SerializeWith +{ + value : self.x, phantom : :: std :: marker :: PhantomData :: >, +}"#; + + assert_eq!(expected, tokens.to_string()); +} + +fn test_integer() { + let ii8 = -1i8; + let ii16 = -1i16; + let ii32 = -1i32; + let ii64 = -1i64; + let ii128 = -1i128; + let iisize = -1isize; + let uu8 = 1u8; + let uu16 = 1u16; + let uu32 = 1u32; + let uu64 = 1u64; + let uu128 = 1u128; + let uusize = 1usize; + + let tokens = quote! { + 1 1i32 1u256 + $ii8 $ii16 $ii32 $ii64 $ii128 $iisize + $uu8 $uu16 $uu32 $uu64 $uu128 $uusize + }; + let expected = r#"1 1i32 1u256 -1i8 -1i16 -1i32 -1i64 -1i128 -1isize 1u8 1u16 1u32 1u64 1u128 +1usize"#; + assert_eq!(expected, tokens.to_string()); +} + +fn test_floating() { + let e32 = 2.345f32; + + let e64 = 2.345f64; + + let tokens = quote! { + $e32 + $e64 + }; + let expected = concat!("2.345f32 2.345f64"); + assert_eq!(expected, tokens.to_string()); +} + +fn test_char() { + let zero = '\u{1}'; + let dollar = '$'; + let pound = '#'; + let quote = '"'; + let apost = '\''; + let newline = '\n'; + let heart = '\u{2764}'; + + let tokens = quote! { + $zero $dollar $pound $quote $apost $newline $heart + }; + let expected = "'\\u{1}' '$' '#' '\"' '\\'' '\\n' '\u{2764}'"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_str() { + let s = "\u{1} a 'b \" c"; + let tokens = quote!($s); + let expected = "\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_string() { + let s = "\u{1} a 'b \" c".to_string(); + let tokens = quote!($s); + let expected = "\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_c_str() { + let s = CStr::from_bytes_with_nul(b"\x01 a 'b \" c\0").unwrap(); + let tokens = quote!($s); + let expected = "c\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_c_string() { + let s = CString::new(&b"\x01 a 'b \" c"[..]).unwrap(); + let tokens = quote!($s); + let expected = "c\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +fn test_interpolated_literal() { + macro_rules! m { + ($literal:literal) => { + quote!($literal) + }; + } + + let tokens = m!(1); + let expected = "1"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(-1); + let expected = "- 1"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(true); + let expected = "true"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(-true); + let expected = "- true"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_ident() { + let foo = Ident::new("Foo", Span::call_site()); + let bar = Ident::new(&format!("Bar{}", 7), Span::call_site()); + let tokens = quote!(struct $foo; enum $bar {}); + let expected = "struct Foo; enum Bar7 {}"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_underscore() { + let tokens = quote!(let _;); + let expected = "let _;"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_duplicate() { + let ch = 'x'; + + let tokens = quote!($ch $ch); + + let expected = "'x' 'x'"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_empty_quote() { + let tokens = quote!(); + assert_eq!("", tokens.to_string()); +} + +fn test_box_str() { + let b = "str".to_owned().into_boxed_str(); + let tokens = quote! { $b }; + assert_eq!("\"str\"", tokens.to_string()); +} + +fn test_cow() { + let owned: Cow = Cow::Owned(Ident::new("owned", Span::call_site())); + + let ident = Ident::new("borrowed", Span::call_site()); + let borrowed = Cow::Borrowed(&ident); + + let tokens = quote! { $owned $borrowed }; + assert_eq!("owned borrowed", tokens.to_string()); +} + +fn test_append_tokens() { + let mut a = quote!(a); + let b = quote!(b); + a.extend(b); + assert_eq!("a b", a.to_string()); +} + +fn test_outer_line_comment() { + let tokens = quote! { + /// doc + }; + let expected = "#[doc = \" doc\"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_inner_line_comment() { + let tokens = quote! { + //! doc + }; + let expected = "# ! [doc = \" doc\"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_outer_block_comment() { + let tokens = quote! { + /** doc */ + }; + let expected = "#[doc = \" doc \"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_inner_block_comment() { + let tokens = quote! { + /*! doc */ + }; + let expected = "# ! [doc = \" doc \"]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_outer_attr() { + let tokens = quote! { + #[inline] + }; + let expected = "#[inline]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_inner_attr() { + let tokens = quote! { + #![no_std] + }; + let expected = "#! [no_std]"; + assert_eq!(expected, tokens.to_string()); +} + +fn test_quote_raw_id() { + let id = quote!(r#raw_id); + assert_eq!(id.to_string(), "r#raw_id"); +} diff --git a/tests/ui/proc-macro/quote/basic.rs b/tests/ui/proc-macro/quote/basic.rs new file mode 100644 index 0000000000000..0336dbb785623 --- /dev/null +++ b/tests/ui/proc-macro/quote/basic.rs @@ -0,0 +1,8 @@ +//@ run-pass +//@ proc-macro: basic.rs + +extern crate basic; + +fn main() { + basic::run_tests!(); +} diff --git a/tests/ui/proc-macro/quote-debug.rs b/tests/ui/proc-macro/quote/debug.rs similarity index 100% rename from tests/ui/proc-macro/quote-debug.rs rename to tests/ui/proc-macro/quote/debug.rs diff --git a/tests/ui/proc-macro/quote-debug.stdout b/tests/ui/proc-macro/quote/debug.stdout similarity index 100% rename from tests/ui/proc-macro/quote-debug.stdout rename to tests/ui/proc-macro/quote/debug.stdout From 2ab9db5442a5a3f7f80cd8cbdf493e56270f7877 Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 9 Jan 2025 02:29:02 +0100 Subject: [PATCH 161/189] Migrate check-fail tests for `proc_macro::quote!` from `quote` crate --- tests/ui/proc-macro/quote/auxiliary/basic.rs | 1 + .../does-not-have-iter-interpolated-dup.rs | 17 +++++++++++++ ...does-not-have-iter-interpolated-dup.stderr | 10 ++++++++ .../quote/does-not-have-iter-interpolated.rs | 17 +++++++++++++ .../does-not-have-iter-interpolated.stderr | 10 ++++++++ .../quote/does-not-have-iter-separated.rs | 13 ++++++++++ .../quote/does-not-have-iter-separated.stderr | 10 ++++++++ .../ui/proc-macro/quote/does-not-have-iter.rs | 13 ++++++++++ .../quote/does-not-have-iter.stderr | 10 ++++++++ tests/ui/proc-macro/quote/not-quotable.rs | 12 ++++++++++ tests/ui/proc-macro/quote/not-quotable.stderr | 24 +++++++++++++++++++ tests/ui/proc-macro/quote/not-repeatable.rs | 16 +++++++++++++ .../ui/proc-macro/quote/not-repeatable.stderr | 10 ++++++++ 13 files changed, 163 insertions(+) create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter-separated.rs create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter.rs create mode 100644 tests/ui/proc-macro/quote/does-not-have-iter.stderr create mode 100644 tests/ui/proc-macro/quote/not-quotable.rs create mode 100644 tests/ui/proc-macro/quote/not-quotable.stderr create mode 100644 tests/ui/proc-macro/quote/not-repeatable.rs create mode 100644 tests/ui/proc-macro/quote/not-repeatable.stderr diff --git a/tests/ui/proc-macro/quote/auxiliary/basic.rs b/tests/ui/proc-macro/quote/auxiliary/basic.rs index 67927e5f6a8a0..c49e9380b8fa1 100644 --- a/tests/ui/proc-macro/quote/auxiliary/basic.rs +++ b/tests/ui/proc-macro/quote/auxiliary/basic.rs @@ -47,6 +47,7 @@ pub fn run_tests(_: TokenStream) -> TokenStream { // - quote_spanned: // - fn test_quote_spanned_impl // - fn test_type_inference_for_span +// - wrong-type-span.rs // - format_ident: // - fn test_format_ident // - fn test_format_ident_strip_raw diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs new file mode 100644 index 0000000000000..2f67ae1bc6edc --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs @@ -0,0 +1,17 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!($($nonrep $nonrep)*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr new file mode 100644 index 0000000000000..5f28a46f3181d --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter-interpolated-dup.rs:16:5 + | +LL | quote!($($nonrep $nonrep)*); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs new file mode 100644 index 0000000000000..1efb3eac64247 --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs @@ -0,0 +1,17 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!($($nonrep)*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr new file mode 100644 index 0000000000000..595aa8587634a --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter-interpolated.rs:16:5 + | +LL | quote!($($nonrep)*); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs new file mode 100644 index 0000000000000..5f2ddabc390da --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs @@ -0,0 +1,13 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + quote!($(a b),*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr new file mode 100644 index 0000000000000..f6f5d7e007d0f --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter-separated.rs:12:5 + | +LL | quote!($(a b),*); + | ^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.rs b/tests/ui/proc-macro/quote/does-not-have-iter.rs new file mode 100644 index 0000000000000..25ffd786cc614 --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter.rs @@ -0,0 +1,13 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +fn main() { + quote!($(a b)*); +} diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.stderr b/tests/ui/proc-macro/quote/does-not-have-iter.stderr new file mode 100644 index 0000000000000..0ed1daffc8cdf --- /dev/null +++ b/tests/ui/proc-macro/quote/does-not-have-iter.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/does-not-have-iter.rs:12:5 + | +LL | quote!($(a b)*); + | ^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/quote/not-quotable.rs b/tests/ui/proc-macro/quote/not-quotable.rs new file mode 100644 index 0000000000000..7e38b4410528a --- /dev/null +++ b/tests/ui/proc-macro/quote/not-quotable.rs @@ -0,0 +1,12 @@ +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use std::net::Ipv4Addr; + +use proc_macro::quote; + +fn main() { + let ip = Ipv4Addr::LOCALHOST; + let _ = quote! { $ip }; //~ ERROR the trait bound `Ipv4Addr: ToTokens` is not satisfied +} diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr new file mode 100644 index 0000000000000..e349b2dce5300 --- /dev/null +++ b/tests/ui/proc-macro/quote/not-quotable.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied + --> $DIR/not-quotable.rs:11:13 + | +LL | let _ = quote! { $ip }; + | ^^^^^^^^^^^^^^ + | | + | the trait `ToTokens` is not implemented for `Ipv4Addr` + | required by a bound introduced by this call + | + = help: the following other types implement trait `ToTokens`: + &T + &mut T + Box + CString + Cow<'_, T> + Option + Rc + bool + and 24 others + = note: this error originates in the macro `quote` (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 E0277`. diff --git a/tests/ui/proc-macro/quote/not-repeatable.rs b/tests/ui/proc-macro/quote/not-repeatable.rs new file mode 100644 index 0000000000000..d115da7318156 --- /dev/null +++ b/tests/ui/proc-macro/quote/not-repeatable.rs @@ -0,0 +1,16 @@ +// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is +// expected to be incorrect. +//@ known-bug: #54722 + +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +struct Ipv4Addr; + +fn main() { + let ip = Ipv4Addr; + let _ = quote! { $($ip)* }; +} diff --git a/tests/ui/proc-macro/quote/not-repeatable.stderr b/tests/ui/proc-macro/quote/not-repeatable.stderr new file mode 100644 index 0000000000000..18fbcd7379858 --- /dev/null +++ b/tests/ui/proc-macro/quote/not-repeatable.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $DIR/not-repeatable.rs:15:13 + | +LL | let _ = quote! { $($ip)* }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: message: `$` must be followed by an ident or `$` in `quote!` + +error: aborting due to 1 previous error + From ef69c3001b387c135038a62902c803f368f7f3bd Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 9 Jan 2025 03:02:23 +0100 Subject: [PATCH 162/189] Fix `proc_macro::quote!` for raw ident --- library/proc_macro/src/quote.rs | 10 ++++++++-- tests/ui/proc-macro/quote/auxiliary/basic.rs | 2 +- tests/ui/proc-macro/quote/debug.rs | 1 + tests/ui/proc-macro/quote/debug.stdout | 19 +++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs index 27c8458a351ca..bcb15912bb65e 100644 --- a/library/proc_macro/src/quote.rs +++ b/library/proc_macro/src/quote.rs @@ -112,8 +112,14 @@ pub fn quote(stream: TokenStream) -> TokenStream { )), &mut ts);) } TokenTree::Ident(tt) => { - minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), + let literal = tt.to_string(); + let (literal, ctor) = if let Some(stripped) = literal.strip_prefix("r#") { + (stripped, minimal_quote!(crate::Ident::new_raw)) + } else { + (literal.as_str(), minimal_quote!(crate::Ident::new)) + }; + minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident((@ ctor)( + (@ TokenTree::from(Literal::string(literal))), (@ quote_span(proc_macro_crate.clone(), tt.span())), )), &mut ts);) } diff --git a/tests/ui/proc-macro/quote/auxiliary/basic.rs b/tests/ui/proc-macro/quote/auxiliary/basic.rs index c49e9380b8fa1..ef726bbfbe3a0 100644 --- a/tests/ui/proc-macro/quote/auxiliary/basic.rs +++ b/tests/ui/proc-macro/quote/auxiliary/basic.rs @@ -34,7 +34,7 @@ pub fn run_tests(_: TokenStream) -> TokenStream { test_inner_block_comment(); test_outer_attr(); test_inner_attr(); - // test_quote_raw_id(); // FIXME: Fix it in a subsequent commit + test_quote_raw_id(); TokenStream::new() } diff --git a/tests/ui/proc-macro/quote/debug.rs b/tests/ui/proc-macro/quote/debug.rs index 11d144d609f5a..ce113079e5678 100644 --- a/tests/ui/proc-macro/quote/debug.rs +++ b/tests/ui/proc-macro/quote/debug.rs @@ -15,5 +15,6 @@ extern crate proc_macro; fn main() { proc_macro::quote! { let hello = "world"; + let r#raw_ident = r#"raw"literal"#; } } diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout index 583599ff97524..3eaad9eb96997 100644 --- a/tests/ui/proc-macro/quote/debug.stdout +++ b/tests/ui/proc-macro/quote/debug.stdout @@ -40,6 +40,25 @@ fn main() { }), &mut ts); crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';', crate::Spacing::Alone)), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let", + crate::Span::recover_proc_macro_span(3))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new_raw("raw_ident", + crate::Span::recover_proc_macro_span(4))), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=', + crate::Spacing::Alone)), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Literal({ + let mut iter = + "r#\"raw\"literal\"#".parse::().unwrap().into_iter(); + if let (Some(crate::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) { + lit.set_span(crate::Span::recover_proc_macro_span(5)); + lit + } else { + ::core::panicking::panic("internal error: entered unreachable code") + } + }), &mut ts); + crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';', + crate::Spacing::Alone)), &mut ts); ts } } From 13e8876ed43454b7104596264cd415032ff5b145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 28 Dec 2024 17:45:17 +0000 Subject: [PATCH 163/189] Add `default_field_values` entry to unstable book --- .../language-features/default-field-values.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/default-field-values.md diff --git a/src/doc/unstable-book/src/language-features/default-field-values.md b/src/doc/unstable-book/src/language-features/default-field-values.md new file mode 100644 index 0000000000000..3143b2d7cae3d --- /dev/null +++ b/src/doc/unstable-book/src/language-features/default-field-values.md @@ -0,0 +1,93 @@ +# `default_field_values` + +The tracking issue for this feature is: [#132162] + +[#132162]: https://github.com/rust-lang/rust/issues/132162 + +The RFC for this feature is: [#3681] + +[#3681]: https://github.com/rust-lang/rfcs/blob/master/text/3681-default-field-values.md + +------------------------ + +The `default_field_values` feature allows users to specify a const value for +individual fields in struct definitions, allowing those to be omitted from +initializers. + +## Examples + +```rust +#![feature(default_field_values)] + +#[derive(Default)] +struct Pet { + name: Option, // impl Default for Pet will use Default::default() for name + age: i128 = 42, // impl Default for Pet will use the literal 42 for age +} + +fn main() { + let a = Pet { name: Some(String::new()), .. }; // Pet { name: Some(""), age: 42 } + let b = Pet::default(); // Pet { name: None, age: 42 } + assert_eq!(a.age, b.age); + // The following would be a compilation error: `name` needs to be specified + // let _ = Pet { .. }; +} +``` + +## `#[derive(Default)]` + +When deriving Default, the provided values are then used. On enum variants, +the variant must still be marked with `#[default]` and have all its fields +with default values. + +```rust +#![feature(default_field_values)] + +#[derive(Default)] +enum A { + #[default] + B { + x: i32 = 0, + y: i32 = 0, + }, + C, +} +``` + +## Enum variants + +This feature also supports enum variants for both specifying default values +and `#[derive(Default)]`. + +## Interaction with `#[non_exhaustive]` + +A struct or enum variant marked with `#[non_exhaustive]` is not allowed to +have default field values. + +## Lints + +When manually implementing the `Default` trait for a type that has default +field values, if any of these are overriden in the impl the +`default_overrides_default_fields` lint will trigger. This lint is in place +to avoid surprising diverging behavior between `S { .. }` and +`S::default()`, where using the same type in both ways could result in +different values. The appropriate way to write a manual `Default` +implementation is to use the functional update syntax: + +```rust +#![feature(default_field_values)] + +struct Pet { + name: String, + age: i128 = 42, // impl Default for Pet will use the literal 42 for age +} + +impl Default for Pet { + fn default() -> Pet { + Pet { + name: "no-name".to_string(), + .. + } + } +} +``` From 9d2e1ed6bd86047f724c8bde4f79561024d13fb8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 9 Jan 2025 22:16:51 +0000 Subject: [PATCH 164/189] Make sure to walk into nested const blocks in RegionResolutionVisitor --- compiler/rustc_hir_analysis/src/check/region.rs | 12 ++++++++---- tests/ui/inline-const/collect-scopes-in-pat.rs | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/ui/inline-const/collect-scopes-in-pat.rs diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index e5f98bdfb7fed..daea2e98b03f8 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -420,10 +420,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // properly, we can't miss any types. match expr.kind { - // Manually recurse over closures and inline consts, because they are the only - // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(&hir::Closure { body, .. }) - | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => { + // Manually recurse over closures, because they are nested bodies + // that share the parent environment. We handle const blocks in + // `visit_inline_const`. + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } @@ -906,6 +906,10 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) { resolve_local(self, Some(l.pat), l.init) } + fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { + let body = self.tcx.hir().body(c.body); + self.visit_body(body); + } } /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; diff --git a/tests/ui/inline-const/collect-scopes-in-pat.rs b/tests/ui/inline-const/collect-scopes-in-pat.rs new file mode 100644 index 0000000000000..024fde537413f --- /dev/null +++ b/tests/ui/inline-const/collect-scopes-in-pat.rs @@ -0,0 +1,16 @@ +// @compile-flags: -Zlint-mir +//@ check-pass + +#![feature(inline_const_pat)] + +fn main() { + match 1 { + const { + || match 0 { + x => 0, + }; + 0 + } => (), + _ => (), + } +} From 9585f3667860b9ccfa3224d5a5e63661e6861d9d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 9 Jan 2025 22:17:10 +0000 Subject: [PATCH 165/189] Rename RegionResolutionVisitor to ScopeResolutionVisitor --- .../rustc_hir_analysis/src/check/region.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index daea2e98b03f8..83c69dc2ef415 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -31,7 +31,7 @@ struct Context { parent: Option<(Scope, ScopeDepth)>, } -struct RegionResolutionVisitor<'tcx> { +struct ScopeResolutionVisitor<'tcx> { tcx: TyCtxt<'tcx>, // The number of expressions and patterns visited in the current body. @@ -71,7 +71,7 @@ struct RegionResolutionVisitor<'tcx> { } /// Records the lifetime of a local variable as `cx.var_parent` -fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) { +fn record_var_lifetime(visitor: &mut ScopeResolutionVisitor<'_>, var_id: hir::ItemLocalId) { match visitor.cx.var_parent { None => { // this can happen in extern fn declarations like @@ -82,7 +82,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::I } } -fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) { +fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) { debug!("resolve_block(blk.hir_id={:?})", blk.hir_id); let prev_cx = visitor.cx; @@ -193,7 +193,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h visitor.cx = prev_cx; } -fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { +fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { fn has_let_expr(expr: &Expr<'_>) -> bool { match &expr.kind { hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), @@ -220,7 +220,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir visitor.cx = prev_cx; } -fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) { +fn resolve_pat<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) { visitor.record_child_scope(Scope { local_id: pat.hir_id.local_id, data: ScopeData::Node }); // If this is a binding then record the lifetime of that binding. @@ -237,7 +237,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir debug!("resolve_pat - post-increment {} pat = {:?}", visitor.expr_and_pat_count, pat); } -fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) { +fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) { let stmt_id = stmt.hir_id.local_id; debug!("resolve_stmt(stmt.id={:?})", stmt_id); @@ -256,7 +256,7 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h visitor.cx.parent = prev_parent; } -fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { +fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); let prev_cx = visitor.cx; @@ -554,7 +554,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h } fn resolve_local<'tcx>( - visitor: &mut RegionResolutionVisitor<'tcx>, + visitor: &mut ScopeResolutionVisitor<'tcx>, pat: Option<&'tcx hir::Pat<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>, ) { @@ -725,7 +725,7 @@ fn resolve_local<'tcx>( /// | ( E& ) /// ``` fn record_rvalue_scope_if_borrow_expr<'tcx>( - visitor: &mut RegionResolutionVisitor<'tcx>, + visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &hir::Expr<'_>, blk_id: Option, ) { @@ -782,7 +782,7 @@ fn resolve_local<'tcx>( } } -impl<'tcx> RegionResolutionVisitor<'tcx> { +impl<'tcx> ScopeResolutionVisitor<'tcx> { /// Records the current parent (if any) as the parent of `child_scope`. /// Returns the depth of `child_scope`. fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth { @@ -838,7 +838,7 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { } } -impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { +impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> { fn visit_block(&mut self, b: &'tcx Block<'tcx>) { resolve_block(self, b); } @@ -926,7 +926,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { } let scope_tree = if let Some(body) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) { - let mut visitor = RegionResolutionVisitor { + let mut visitor = ScopeResolutionVisitor { tcx, scope_tree: ScopeTree::default(), expr_and_pat_count: 0, From a75617c223ca4476625c20565a3e1ff51d384102 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 16 Nov 2024 01:55:07 +0100 Subject: [PATCH 166/189] Foo != Foo under layout randomization previously field ordering was using the same seed for all instances of Foo, now we pass seed values through the layout tree so that not only the struct itself affects layout but also its fields --- compiler/rustc_abi/src/layout.rs | 37 ++++++++++++++++++++++-- compiler/rustc_abi/src/lib.rs | 39 ++++++++++++++++++++++++++ compiler/rustc_middle/src/ty/layout.rs | 1 + compiler/rustc_ty_utils/src/layout.rs | 10 +++++++ tests/ui/layout/randomize.rs | 29 +++++++++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 tests/ui/layout/randomize.rs diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 226a46f605cc4..3b897c1cb3e51 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -119,6 +119,8 @@ impl LayoutCalculator { .chain(Niche::from_scalar(dl, Size::ZERO, a)) .max_by_key(|niche| niche.available(dl)); + let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes()); + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { @@ -131,6 +133,7 @@ impl LayoutCalculator { size, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: combined_seed, } } @@ -223,6 +226,7 @@ impl LayoutCalculator { size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: 0, } } @@ -385,6 +389,11 @@ impl LayoutCalculator { return Err(LayoutCalculatorError::EmptyUnion); }; + let combined_seed = only_variant + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), @@ -394,6 +403,7 @@ impl LayoutCalculator { size: size.align_to(align.abi), max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }) } @@ -650,6 +660,11 @@ impl LayoutCalculator { BackendRepr::Memory { sized: true } }; + let combined_seed = variant_layouts + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + let layout = LayoutData { variants: Variants::Multiple { tag: niche_scalar, @@ -671,6 +686,7 @@ impl LayoutCalculator { align, max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }; Some(TmpLayout { layout, variants: variant_layouts }) @@ -961,6 +977,11 @@ impl LayoutCalculator { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); + let combined_seed = layout_variants + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, @@ -978,6 +999,7 @@ impl LayoutCalculator { size, max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }; let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; @@ -1029,6 +1051,8 @@ impl LayoutCalculator { let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; let mut inverse_memory_index: IndexVec = fields.indices().collect(); + let field_seed = + fields.raw.iter().fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed)); let optimize_field_order = !repr.inhibit_struct_field_reordering(); if optimize_field_order && fields.len() > 1 { let end = @@ -1046,8 +1070,9 @@ impl LayoutCalculator { use rand::seq::SliceRandom; // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field // ordering. - let mut rng = - rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64( + field_seed.wrapping_add(repr.field_shuffle_seed), + ); // Shuffle the ordering of the fields. optimizing.shuffle(&mut rng); @@ -1344,6 +1369,13 @@ impl LayoutCalculator { unadjusted_abi_align }; + // a transparent struct only has a single field, so its seed should be the same as the one we pass forward + let seed = if repr.transparent() { + field_seed + } else { + field_seed.wrapping_add(repr.field_shuffle_seed) + }; + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, @@ -1353,6 +1385,7 @@ impl LayoutCalculator { size, max_repr_align, unadjusted_abi_align, + randomization_seed: seed, }) } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 7fa869a509cc3..8ad33749f3473 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1719,6 +1719,18 @@ pub struct LayoutData { /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment /// in some cases. pub unadjusted_abi_align: Align, + + /// The randomization seed based on this type's own repr and its fields. + /// + /// Since randomization is toggled on a per-crate basis even crates that do not have randomization + /// enabled should still calculate a seed so that downstream uses can use it to distinguish different + /// types. + /// + /// For every T and U for which we do not guarantee that a repr(Rust) `Foo` can be coerced or + /// transmuted to `Foo` we aim to create probalistically distinct seeds so that Foo can choose + /// to reorder its fields based on that information. The current implementation is a conservative + /// approximation of this goal. + pub randomization_seed: u64, } impl LayoutData { @@ -1739,6 +1751,30 @@ impl LayoutData { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.size(cx); let align = scalar.align(cx); + + let range = scalar.valid_range(cx); + + // All primitive types for which we don't have subtype coercions should get a distinct seed, + // so that types wrapping them can use randomization to arrive at distinct layouts. + // + // Some type information is already lost at this point, so as an approximation we derive + // the seed from what remains. For example on 64-bit targets usize and u64 can no longer + // be distinguished. + let randomization_seed = size + .bytes() + .wrapping_add( + match scalar.primitive() { + Primitive::Int(_, true) => 1, + Primitive::Int(_, false) => 2, + Primitive::Float(_) => 3, + Primitive::Pointer(_) => 4, + } << 32, + ) + // distinguishes references from pointers + .wrapping_add((range.start as u64).rotate_right(16)) + // distinguishes char from u32 and bool from u8 + .wrapping_add((range.end as u64).rotate_right(16)); + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, @@ -1748,6 +1784,7 @@ impl LayoutData { align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed, } } } @@ -1770,6 +1807,7 @@ where variants, max_repr_align, unadjusted_abi_align, + ref randomization_seed, } = self; f.debug_struct("Layout") .field("size", size) @@ -1780,6 +1818,7 @@ where .field("variants", variants) .field("max_repr_align", max_repr_align) .field("unadjusted_abi_align", unadjusted_abi_align) + .field("randomization_seed", randomization_seed) .finish() } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6e6da6de749a1..8d4d127607d34 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -770,6 +770,7 @@ where size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: tcx.data_layout.i8_align.abi, + randomization_seed: 0, }) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9f138cf1275d2..fae787f9a40b3 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -347,6 +347,7 @@ fn layout_of_uncached<'tcx>( size, max_repr_align: None, unadjusted_abi_align: element.align.abi, + randomization_seed: element.randomization_seed.wrapping_add(count), }) } ty::Slice(element) => { @@ -360,6 +361,8 @@ fn layout_of_uncached<'tcx>( size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: element.align.abi, + // adding a randomly chosen value to distinguish slices + randomization_seed: element.randomization_seed.wrapping_add(0x2dcba99c39784102), }) } ty::Str => tcx.mk_layout(LayoutData { @@ -371,6 +374,8 @@ fn layout_of_uncached<'tcx>( size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, + // another random value + randomization_seed: 0xc1325f37d127be22, }), // Odd unit types. @@ -542,6 +547,7 @@ fn layout_of_uncached<'tcx>( align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: e_ly.randomization_seed.wrapping_add(e_len), }) } @@ -999,6 +1005,9 @@ fn coroutine_layout<'tcx>( BackendRepr::Memory { sized: true } }; + // this is similar to how ReprOptions populates its field_shuffle_seed + let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash().as_u64(); + let layout = tcx.mk_layout(LayoutData { variants: Variants::Multiple { tag, @@ -1019,6 +1028,7 @@ fn coroutine_layout<'tcx>( align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: def_hash, }); debug!("coroutine layout ({:?}): {:#?}", ty, layout); Ok(layout) diff --git a/tests/ui/layout/randomize.rs b/tests/ui/layout/randomize.rs new file mode 100644 index 0000000000000..be895252a1b23 --- /dev/null +++ b/tests/ui/layout/randomize.rs @@ -0,0 +1,29 @@ +//@ build-pass +//@ revisions: normal randomize-layout +//@ [randomize-layout]compile-flags: -Zrandomize-layout + +#![crate_type = "lib"] + +struct Foo(u32, T, u8); + +struct Wrapper(T); + +#[repr(transparent)] +struct TransparentWrapper(u16); + +const _: () = { + // behavior of the current implementation, not guaranteed + #[cfg(not(randomize_layout))] + assert!(std::mem::offset_of!(Foo::, 1) == std::mem::offset_of!(Foo::>, 1)); + + // under randomization Foo != Foo + #[cfg(randomize_layout)] + assert!(std::mem::offset_of!(Foo::, 1) != std::mem::offset_of!(Foo::>, 1)); + + // but repr(transparent) should make them the same again. + // maybe not strictly guaranteed? but UCG has been leaning in that direction at least + #[cfg(randomize_layout)] + assert!( + std::mem::offset_of!(Foo::, 1) == std::mem::offset_of!(Foo::, 1) + ); +}; From d7fb729d393e40919adfa0738a205c24c821808d Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 23 Dec 2024 23:17:02 +0100 Subject: [PATCH 167/189] adjust UI tests --- tests/ui/abi/c-zst.aarch64-darwin.stderr | 2 + tests/ui/abi/c-zst.powerpc-linux.stderr | 2 + tests/ui/abi/c-zst.s390x-linux.stderr | 2 + tests/ui/abi/c-zst.sparc64-linux.stderr | 2 + tests/ui/abi/c-zst.x86_64-linux.stderr | 2 + .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 2 + tests/ui/abi/debug.rs | 1 + tests/ui/abi/debug.stderr | 46 +++++++++++---- tests/ui/abi/sysv64-zst.stderr | 2 + tests/ui/abi/win64-zst.x86_64-linux.stderr | 2 + .../abi/win64-zst.x86_64-windows-gnu.stderr | 2 + .../abi/win64-zst.x86_64-windows-msvc.stderr | 2 + tests/ui/layout/debug.rs | 1 + tests/ui/layout/debug.stderr | 56 ++++++++++++------- tests/ui/layout/hexagon-enum.rs | 1 + tests/ui/layout/hexagon-enum.stderr | 20 +++++-- ...6158-scalarpair-payload-might-be-uninit.rs | 1 + ...-scalarpair-payload-might-be-uninit.stderr | 27 +++++++-- .../ui/layout/issue-96185-overaligned-enum.rs | 1 + .../issue-96185-overaligned-enum.stderr | 10 +++- tests/ui/layout/thumb-enum.rs | 1 + tests/ui/layout/thumb-enum.stderr | 20 +++++-- .../ui/layout/zero-sized-array-enum-niche.rs | 1 + .../layout/zero-sized-array-enum-niche.stderr | 21 +++++-- ...-variants.aarch64-unknown-linux-gnu.stderr | 14 ++++- ...-c-dead-variants.armebv7r-none-eabi.stderr | 14 ++++- ...-dead-variants.i686-pc-windows-msvc.stderr | 14 ++++- tests/ui/repr/repr-c-dead-variants.rs | 1 + ...d-variants.x86_64-unknown-linux-gnu.stderr | 14 ++++- tests/ui/repr/repr-c-int-dead-variants.rs | 1 + tests/ui/repr/repr-c-int-dead-variants.stderr | 14 ++++- tests/ui/type/pattern_types/range_patterns.rs | 1 + .../type/pattern_types/range_patterns.stderr | 19 +++++-- 33 files changed, 248 insertions(+), 71 deletions(-) diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 7d384bc875f98..d9742612bcfd2 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index 7980710bab676..0e98b5f806bc2 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Indirect { @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index 7980710bab676..0e98b5f806bc2 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Indirect { @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index 7980710bab676..0e98b5f806bc2 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Indirect { @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 7d384bc875f98..d9742612bcfd2 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index 7980710bab676..0e98b5f806bc2 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Indirect { @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 565743bf978ea..6dbc316146412 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -1,4 +1,5 @@ //@ normalize-stderr: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" //@ normalize-stderr: "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE" //@ normalize-stderr: "(can_unwind): (true|false)" -> "$1: $$SOME_BOOL" //@ normalize-stderr: "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL" diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index aa51c42c58dc4..e550e5bfcf3c3 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -25,6 +25,7 @@ error: fn_abi_of(test) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -71,6 +72,7 @@ error: fn_abi_of(test) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -87,7 +89,7 @@ error: fn_abi_of(test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:15:1 + --> $DIR/debug.rs:16:1 | LL | fn test(_x: u8) -> bool { true } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,6 +130,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -165,6 +168,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -181,7 +185,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:18:1 + --> $DIR/debug.rs:19:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -214,6 +218,7 @@ error: fn_abi_of(test_generic) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -248,6 +253,7 @@ error: fn_abi_of(test_generic) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -257,13 +263,13 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:21:1 + --> $DIR/debug.rs:22:1 | LL | fn test_generic(_x: *const T) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:24:1 + --> $DIR/debug.rs:25:1 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -296,6 +302,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -330,6 +337,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -366,6 +374,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -400,6 +409,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -409,7 +419,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:40:1 + --> $DIR/debug.rs:41:1 | LL | type TestAbiNe = (fn(u8), fn(u32)); | ^^^^^^^^^^^^^^ @@ -439,6 +449,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Indirect { @@ -477,6 +488,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -510,6 +522,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Indirect { @@ -548,6 +561,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -557,7 +571,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:43:1 + --> $DIR/debug.rs:44:1 | LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); | ^^^^^^^^^^^^^^^^^^^^ @@ -589,6 +603,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -623,6 +638,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -659,6 +675,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -693,6 +710,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -702,7 +720,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:46:1 + --> $DIR/debug.rs:47:1 | LL | type TestAbiNeFloat = (fn(f32), fn(u32)); | ^^^^^^^^^^^^^^^^^^^ @@ -735,6 +753,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -769,6 +788,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -805,6 +825,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -839,6 +860,7 @@ error: ABIs are not compatible }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -848,13 +870,13 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:50:1 + --> $DIR/debug.rs:51:1 | LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:53:46 + --> $DIR/debug.rs:54:46 | LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -863,7 +885,7 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = note: only the last element of a tuple may have a dynamically sized type error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:28:5 + --> $DIR/debug.rs:29:5 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -906,6 +928,7 @@ error: fn_abi_of(assoc_test) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Direct( @@ -942,6 +965,7 @@ error: fn_abi_of(assoc_test) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, }, }, mode: Ignore, @@ -951,7 +975,7 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:33:5 + --> $DIR/debug.rs:34:5 | LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 8e1791e27d27c..781e9b2f4c9d5 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/win64-zst.x86_64-linux.stderr b/tests/ui/abi/win64-zst.x86_64-linux.stderr index 76d90670eb1dd..a28a59fdd8d02 100644 --- a/tests/ui/abi/win64-zst.x86_64-linux.stderr +++ b/tests/ui/abi/win64-zst.x86_64-linux.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr index 7ee90e2474413..cf0cc00c5ed07 100644 --- a/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr +++ b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Indirect { @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr b/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr index 76d90670eb1dd..a28a59fdd8d02 100644 --- a/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr +++ b/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: 0, }, }, mode: Ignore, diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs index 5602c4e711f61..81dc72852543d 100644 --- a/tests/ui/layout/debug.rs +++ b/tests/ui/layout/debug.rs @@ -1,4 +1,5 @@ //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" #![feature(never_type, rustc_attrs, type_alias_impl_trait, repr_simd)] #![crate_type = "lib"] diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index bd31665dac1f7..1fc55511384f2 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -1,5 +1,5 @@ error: unions cannot have zero fields - --> $DIR/debug.rs:82:1 + --> $DIR/debug.rs:83:1 | LL | union EmptyUnion {} | ^^^^^^^^^^^^^^^^^^^ @@ -61,6 +61,7 @@ error: layout_of(E) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(12 bytes), @@ -87,13 +88,15 @@ error: layout_of(E) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:7:1 + --> $DIR/debug.rs:8:1 | LL | enum E { Foo, Bar(!, i32, i32) } | ^^^^^^ @@ -138,8 +141,9 @@ error: layout_of(S) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:10:1 + --> $DIR/debug.rs:11:1 | LL | struct S { f1: i32, f2: (), f3: i32 } | ^^^^^^^^ @@ -162,8 +166,9 @@ error: layout_of(U) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:13:1 + --> $DIR/debug.rs:14:1 | LL | union U { f1: (i32, i32), f3: i32 } | ^^^^^^^ @@ -255,6 +260,7 @@ error: layout_of(Result) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(8 bytes), @@ -292,13 +298,15 @@ error: layout_of(Result) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:16:1 + --> $DIR/debug.rs:17:1 | LL | type Test = Result; | ^^^^^^^^^ @@ -325,8 +333,9 @@ error: layout_of(i32) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:19:1 + --> $DIR/debug.rs:20:1 | LL | type T = impl std::fmt::Debug; | ^^^^^^ @@ -349,8 +358,9 @@ error: layout_of(V) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:25:1 + --> $DIR/debug.rs:26:1 | LL | pub union V { | ^^^^^^^^^^^ @@ -373,8 +383,9 @@ error: layout_of(W) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:31:1 + --> $DIR/debug.rs:32:1 | LL | pub union W { | ^^^^^^^^^^^ @@ -397,8 +408,9 @@ error: layout_of(Y) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:37:1 + --> $DIR/debug.rs:38:1 | LL | pub union Y { | ^^^^^^^^^^^ @@ -421,8 +433,9 @@ error: layout_of(P1) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:44:1 + --> $DIR/debug.rs:45:1 | LL | union P1 { x: u32 } | ^^^^^^^^ @@ -445,8 +458,9 @@ error: layout_of(P2) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:48:1 + --> $DIR/debug.rs:49:1 | LL | union P2 { x: (u32, u32) } | ^^^^^^^^ @@ -469,8 +483,9 @@ error: layout_of(P3) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:56:1 + --> $DIR/debug.rs:57:1 | LL | union P3 { x: F32x4 } | ^^^^^^^^ @@ -493,8 +508,9 @@ error: layout_of(P4) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:60:1 + --> $DIR/debug.rs:61:1 | LL | union P4 { x: E } | ^^^^^^^^ @@ -522,8 +538,9 @@ error: layout_of(P5) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:64:1 + --> $DIR/debug.rs:65:1 | LL | union P5 { zst: [u16; 0], byte: u8 } | ^^^^^^^^ @@ -551,20 +568,21 @@ error: layout_of(MaybeUninit) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/debug.rs:67:1 + --> $DIR/debug.rs:68:1 | LL | type X = std::mem::MaybeUninit; | ^^^^^^ error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases - --> $DIR/debug.rs:70:1 + --> $DIR/debug.rs:71:1 | LL | const C: () = (); | ^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:78:19 + --> $DIR/debug.rs:79:19 | LL | type Impossible = (str, str); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -573,13 +591,13 @@ LL | type Impossible = (str, str); = note: only the last element of a tuple may have a dynamically sized type error: the type `EmptyUnion` has an unknown layout - --> $DIR/debug.rs:82:1 + --> $DIR/debug.rs:83:1 | LL | union EmptyUnion {} | ^^^^^^^^^^^^^^^^ error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases - --> $DIR/debug.rs:74:5 + --> $DIR/debug.rs:75:5 | LL | const C: () = (); | ^^^^^^^^^^^ diff --git a/tests/ui/layout/hexagon-enum.rs b/tests/ui/layout/hexagon-enum.rs index e3a5c53671d40..5fa12e479e7db 100644 --- a/tests/ui/layout/hexagon-enum.rs +++ b/tests/ui/layout/hexagon-enum.rs @@ -1,4 +1,5 @@ //@ compile-flags: --target hexagon-unknown-linux-musl +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" //@ needs-llvm-components: hexagon // // Verify that the hexagon targets implement the repr(C) for enums correctly. diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index 59fe667923f11..96f0a8c874086 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -61,13 +61,15 @@ error: layout_of(A) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/hexagon-enum.rs:16:1 + --> $DIR/hexagon-enum.rs:17:1 | LL | enum A { Apple } | ^^^^^^ @@ -135,13 +137,15 @@ error: layout_of(B) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/hexagon-enum.rs:20:1 + --> $DIR/hexagon-enum.rs:21:1 | LL | enum B { Banana = 255, } | ^^^^^^ @@ -209,13 +213,15 @@ error: layout_of(C) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, } - --> $DIR/hexagon-enum.rs:24:1 + --> $DIR/hexagon-enum.rs:25:1 | LL | enum C { Chaenomeles = 256, } | ^^^^^^ @@ -283,13 +289,15 @@ error: layout_of(P) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/hexagon-enum.rs:28:1 + --> $DIR/hexagon-enum.rs:29:1 | LL | enum P { Peach = 0x1000_0000isize, } | ^^^^^^ @@ -357,13 +365,15 @@ error: layout_of(T) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/hexagon-enum.rs:34:1 + --> $DIR/hexagon-enum.rs:35:1 | LL | enum T { Tangerine = TANGERINE as isize } | ^^^^^^ diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs index 328d204aa3cda..ab7e0897ce32c 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs @@ -1,4 +1,5 @@ //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" #![crate_type = "lib"] #![feature(rustc_attrs)] diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index ca041fb539b93..cd9e4c0278150 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -83,6 +83,7 @@ error: layout_of(MissingPayloadField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(1 bytes), @@ -103,13 +104,15 @@ error: layout_of(MissingPayloadField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1 + --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:17:1 | LL | pub enum MissingPayloadField { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -201,6 +204,7 @@ error: layout_of(CommonPayloadField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -238,13 +242,15 @@ error: layout_of(CommonPayloadField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1 + --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:26:1 | LL | pub enum CommonPayloadField { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -334,6 +340,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -370,13 +377,15 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1 + --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:34:1 | LL | pub enum CommonPayloadFieldIsMaybeUninit { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -482,6 +491,7 @@ error: layout_of(NicheFirst) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(0 bytes), @@ -502,6 +512,7 @@ error: layout_of(NicheFirst) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(0 bytes), @@ -522,13 +533,15 @@ error: layout_of(NicheFirst) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1 + --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:42:1 | LL | pub enum NicheFirst { | ^^^^^^^^^^^^^^^^^^^ @@ -634,6 +647,7 @@ error: layout_of(NicheSecond) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(0 bytes), @@ -654,6 +668,7 @@ error: layout_of(NicheSecond) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(0 bytes), @@ -674,13 +689,15 @@ error: layout_of(NicheSecond) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1 + --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:51:1 | LL | pub enum NicheSecond { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/issue-96185-overaligned-enum.rs b/tests/ui/layout/issue-96185-overaligned-enum.rs index 341233a7890eb..19da169105cec 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.rs +++ b/tests/ui/layout/issue-96185-overaligned-enum.rs @@ -1,4 +1,5 @@ //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" #![crate_type = "lib"] #![feature(rustc_attrs)] diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index bc40a2aa482ed..15a3f6004f50f 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -57,6 +57,7 @@ error: layout_of(Aligned1) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(8 bytes), @@ -79,6 +80,7 @@ error: layout_of(Aligned1) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, @@ -86,8 +88,9 @@ error: layout_of(Aligned1) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96185-overaligned-enum.rs:8:1 + --> $DIR/issue-96185-overaligned-enum.rs:9:1 | LL | pub enum Aligned1 { | ^^^^^^^^^^^^^^^^^ @@ -157,6 +160,7 @@ error: layout_of(Aligned2) = Layout { Align(1 bytes), ), unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(1 bytes), @@ -179,6 +183,7 @@ error: layout_of(Aligned2) = Layout { Align(1 bytes), ), unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, @@ -186,8 +191,9 @@ error: layout_of(Aligned2) = Layout { Align(1 bytes), ), unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/issue-96185-overaligned-enum.rs:16:1 + --> $DIR/issue-96185-overaligned-enum.rs:17:1 | LL | pub enum Aligned2 { | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/thumb-enum.rs b/tests/ui/layout/thumb-enum.rs index 57a9a2d813709..2381d9d02926d 100644 --- a/tests/ui/layout/thumb-enum.rs +++ b/tests/ui/layout/thumb-enum.rs @@ -1,4 +1,5 @@ //@ compile-flags: --target thumbv8m.main-none-eabihf +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" //@ needs-llvm-components: arm // // Verify that thumb targets implement the repr(C) for enums correctly. diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index bf043af586b1c..120081d193c69 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -61,13 +61,15 @@ error: layout_of(A) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/thumb-enum.rs:16:1 + --> $DIR/thumb-enum.rs:17:1 | LL | enum A { Apple } | ^^^^^^ @@ -135,13 +137,15 @@ error: layout_of(B) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/thumb-enum.rs:20:1 + --> $DIR/thumb-enum.rs:21:1 | LL | enum B { Banana = 255, } | ^^^^^^ @@ -209,13 +213,15 @@ error: layout_of(C) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, } - --> $DIR/thumb-enum.rs:24:1 + --> $DIR/thumb-enum.rs:25:1 | LL | enum C { Chaenomeles = 256, } | ^^^^^^ @@ -283,13 +289,15 @@ error: layout_of(P) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/thumb-enum.rs:28:1 + --> $DIR/thumb-enum.rs:29:1 | LL | enum P { Peach = 0x1000_0000isize, } | ^^^^^^ @@ -357,13 +365,15 @@ error: layout_of(T) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/thumb-enum.rs:34:1 + --> $DIR/thumb-enum.rs:35:1 | LL | enum T { Tangerine = TANGERINE as isize } | ^^^^^^ diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs index 152f44bd86375..d3ff016d8aa23 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.rs +++ b/tests/ui/layout/zero-sized-array-enum-niche.rs @@ -1,4 +1,5 @@ //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" #![crate_type = "lib"] #![feature(rustc_attrs)] diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index d61408098df7f..b6fcc14c063c5 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -59,6 +59,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -92,13 +93,15 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/zero-sized-array-enum-niche.rs:13:1 + --> $DIR/zero-sized-array-enum-niche.rs:14:1 | LL | type AlignedResult = Result<[u32; 0], bool>; | ^^^^^^^^^^^^^^^^^^ @@ -164,6 +167,7 @@ error: layout_of(MultipleAlignments) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), + randomization_seed: $SEED, }, Layout { size: Size(4 bytes), @@ -188,6 +192,7 @@ error: layout_of(MultipleAlignments) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -221,13 +226,15 @@ error: layout_of(MultipleAlignments) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/zero-sized-array-enum-niche.rs:21:1 + --> $DIR/zero-sized-array-enum-niche.rs:22:1 | LL | enum MultipleAlignments { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -293,6 +300,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(3 bytes), @@ -326,13 +334,15 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/zero-sized-array-enum-niche.rs:37:1 + --> $DIR/zero-sized-array-enum-niche.rs:38:1 | LL | type NicheLosesToTagged = Result<[u32; 0], Packed>>; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -402,6 +412,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -435,13 +446,15 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/zero-sized-array-enum-niche.rs:44:1 + --> $DIR/zero-sized-array-enum-niche.rs:45:1 | LL | type NicheWinsOverTagged = Result<[u32; 0], Packed>; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr index 64a0cb7f31a14..8e8f1d159b740 100644 --- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:38:1 + --> $DIR/repr-c-dead-variants.rs:39:1 | LL | enum Univariant { | ^^^^^^^^^^^^^^^ @@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(8 bytes), @@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:45:1 + --> $DIR/repr-c-dead-variants.rs:46:1 | LL | enum TwoVariants { | ^^^^^^^^^^^^^^^^ @@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, Layout { size: Size(16 bytes), @@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, ], }, @@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:57:1 + --> $DIR/repr-c-dead-variants.rs:58:1 | LL | enum DeadBranchHasOtherField { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr index 5c4daa6d51977..2cd0960ce3eec 100644 --- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:38:1 + --> $DIR/repr-c-dead-variants.rs:39:1 | LL | enum Univariant { | ^^^^^^^^^^^^^^^ @@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:45:1 + --> $DIR/repr-c-dead-variants.rs:46:1 | LL | enum TwoVariants { | ^^^^^^^^^^^^^^^^ @@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, Layout { size: Size(16 bytes), @@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, ], }, @@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:57:1 + --> $DIR/repr-c-dead-variants.rs:58:1 | LL | enum DeadBranchHasOtherField { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr index 64a0cb7f31a14..8e8f1d159b740 100644 --- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:38:1 + --> $DIR/repr-c-dead-variants.rs:39:1 | LL | enum Univariant { | ^^^^^^^^^^^^^^^ @@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(8 bytes), @@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:45:1 + --> $DIR/repr-c-dead-variants.rs:46:1 | LL | enum TwoVariants { | ^^^^^^^^^^^^^^^^ @@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, Layout { size: Size(16 bytes), @@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, ], }, @@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:57:1 + --> $DIR/repr-c-dead-variants.rs:58:1 | LL | enum DeadBranchHasOtherField { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs index 3e8ae3d096d86..99f20982a9960 100644 --- a/tests/ui/repr/repr-c-dead-variants.rs +++ b/tests/ui/repr/repr-c-dead-variants.rs @@ -7,6 +7,7 @@ // See also: repr-c-int-dead-variants.rs //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" // This test depends on the value of the `c_enum_min_bits` target option. // As there's no way to actually check it from UI test, we only run this test on a subset of archs. diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr index 64a0cb7f31a14..8e8f1d159b740 100644 --- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:38:1 + --> $DIR/repr-c-dead-variants.rs:39:1 | LL | enum Univariant { | ^^^^^^^^^^^^^^^ @@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, Layout { size: Size(8 bytes), @@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:45:1 + --> $DIR/repr-c-dead-variants.rs:46:1 | LL | enum TwoVariants { | ^^^^^^^^^^^^^^^^ @@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, Layout { size: Size(16 bytes), @@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, ], }, @@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-dead-variants.rs:57:1 + --> $DIR/repr-c-dead-variants.rs:58:1 | LL | enum DeadBranchHasOtherField { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs index 627569e080d4c..723e573024402 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.rs +++ b/tests/ui/repr/repr-c-int-dead-variants.rs @@ -4,6 +4,7 @@ // See also: repr-c-dead-variants.rs //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" // A simple uninhabited type. enum Void {} diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr index 75005a64523a3..fa08b323dec2a 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.stderr +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -55,13 +55,15 @@ error: layout_of(UnivariantU8) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-int-dead-variants.rs:14:1 + --> $DIR/repr-c-int-dead-variants.rs:15:1 | LL | enum UnivariantU8 { | ^^^^^^^^^^^^^^^^^ @@ -137,6 +139,7 @@ error: layout_of(TwoVariantsU8) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(2 bytes), @@ -173,13 +176,15 @@ error: layout_of(TwoVariantsU8) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-int-dead-variants.rs:21:1 + --> $DIR/repr-c-int-dead-variants.rs:22:1 | LL | enum TwoVariantsU8 { | ^^^^^^^^^^^^^^^^^^ @@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, Layout { size: Size(16 bytes), @@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, }, ], }, @@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { Align(8 bytes), ), unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, } - --> $DIR/repr-c-int-dead-variants.rs:33:1 + --> $DIR/repr-c-int-dead-variants.rs:34:1 | LL | enum DeadBranchHasOtherFieldU8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs index ff87444b49e30..446a33195c8bd 100644 --- a/tests/ui/type/pattern_types/range_patterns.rs +++ b/tests/ui/type/pattern_types/range_patterns.rs @@ -3,6 +3,7 @@ #![allow(incomplete_features)] //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" use std::pat::pattern_type; diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index 0eed7c2ce1ce8..7da8cfd4dbc2d 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -36,8 +36,9 @@ error: layout_of(NonZero) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/range_patterns.rs:10:1 + --> $DIR/range_patterns.rs:11:1 | LL | type X = std::num::NonZeroU32; | ^^^^^^ @@ -73,8 +74,9 @@ error: layout_of((u32) is 1..=) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/range_patterns.rs:12:1 + --> $DIR/range_patterns.rs:13:1 | LL | type Y = pattern_type!(u32 is 1..); | ^^^^^^ @@ -137,6 +139,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(4 bytes), @@ -176,13 +179,15 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/range_patterns.rs:14:1 + --> $DIR/range_patterns.rs:15:1 | LL | type Z = Option; | ^^^^^^ @@ -245,6 +250,7 @@ error: layout_of(Option>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, }, Layout { size: Size(4 bytes), @@ -284,13 +290,15 @@ error: layout_of(Option>) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, }, ], }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/range_patterns.rs:16:1 + --> $DIR/range_patterns.rs:17:1 | LL | type A = Option; | ^^^^^^ @@ -333,8 +341,9 @@ error: layout_of(NonZeroU32New) = Layout { }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), + randomization_seed: $SEED, } - --> $DIR/range_patterns.rs:18:1 + --> $DIR/range_patterns.rs:19:1 | LL | struct NonZeroU32New(pattern_type!(u32 is 1..)); | ^^^^^^^^^^^^^^^^^^^^ From 56889dd826f0e306fb08c1faa903b35daf59806a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 16 Nov 2024 02:22:28 +0100 Subject: [PATCH 168/189] exclude unsizable tail from randomization seed calculation --- compiler/rustc_abi/src/layout.rs | 22 +++++++++------------- tests/ui/layout/randomize.rs | 7 ++++--- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 3b897c1cb3e51..b8773f9ff38f6 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1051,15 +1051,16 @@ impl LayoutCalculator { let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; let mut inverse_memory_index: IndexVec = fields.indices().collect(); - let field_seed = - fields.raw.iter().fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed)); let optimize_field_order = !repr.inhibit_struct_field_reordering(); - if optimize_field_order && fields.len() > 1 { - let end = - if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index.raw[..end]; - let fields_excluding_tail = &fields.raw[..end]; + let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; + let optimizing = &mut inverse_memory_index.raw[..end]; + let fields_excluding_tail = &fields.raw[..end]; + // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts. + let field_seed = fields_excluding_tail + .iter() + .fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed)); + if optimize_field_order && fields.len() > 1 { // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts // we don't guarantee. @@ -1369,12 +1370,7 @@ impl LayoutCalculator { unadjusted_abi_align }; - // a transparent struct only has a single field, so its seed should be the same as the one we pass forward - let seed = if repr.transparent() { - field_seed - } else { - field_seed.wrapping_add(repr.field_shuffle_seed) - }; + let seed = field_seed.wrapping_add(repr.field_shuffle_seed); Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, diff --git a/tests/ui/layout/randomize.rs b/tests/ui/layout/randomize.rs index be895252a1b23..da8414bc3e2df 100644 --- a/tests/ui/layout/randomize.rs +++ b/tests/ui/layout/randomize.rs @@ -20,10 +20,11 @@ const _: () = { #[cfg(randomize_layout)] assert!(std::mem::offset_of!(Foo::, 1) != std::mem::offset_of!(Foo::>, 1)); - // but repr(transparent) should make them the same again. - // maybe not strictly guaranteed? but UCG has been leaning in that direction at least + // Even transparent wrapper inner types get a different layout since associated type + // pecialization could result in the outer type behaving differently depending on the exact + // inner type. #[cfg(randomize_layout)] assert!( - std::mem::offset_of!(Foo::, 1) == std::mem::offset_of!(Foo::, 1) + std::mem::offset_of!(Foo::, 1) != std::mem::offset_of!(Foo::, 1) ); }; From 8b1de1682fcfaa2f56d6e4b98e1f18eb1bfcee55 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 16 Nov 2024 02:49:03 +0100 Subject: [PATCH 169/189] also initialize Layout field in rust-analyzer --- src/tools/rust-analyzer/crates/hir-ty/src/layout.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 0c1f63880cd2a..108171586ea89 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -197,6 +197,7 @@ fn layout_of_simd_ty( align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: 0, })) } @@ -313,6 +314,7 @@ pub fn layout_of_ty_query( size, max_repr_align: None, unadjusted_abi_align: element.align.abi, + randomization_seed: 0, } } TyKind::Slice(element) => { @@ -326,6 +328,7 @@ pub fn layout_of_ty_query( size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: element.align.abi, + randomization_seed: 0, } } TyKind::Str => Layout { @@ -337,6 +340,7 @@ pub fn layout_of_ty_query( size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: 0, }, // Potentially-wide pointers. TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => { From d89b6d5ac6ceb7f735c8d2c7397fb6bb0e0e3020 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 9 Jan 2025 00:50:47 +0100 Subject: [PATCH 170/189] test that coercions still work under randomization --- tests/ui/layout/randomize.rs | 48 ++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/tests/ui/layout/randomize.rs b/tests/ui/layout/randomize.rs index da8414bc3e2df..27e99327a3196 100644 --- a/tests/ui/layout/randomize.rs +++ b/tests/ui/layout/randomize.rs @@ -1,18 +1,23 @@ -//@ build-pass +//@ run-pass //@ revisions: normal randomize-layout -//@ [randomize-layout]compile-flags: -Zrandomize-layout +//@ [randomize-layout]compile-flags: -Zrandomize-layout -Zlayout-seed=2 -#![crate_type = "lib"] +#![feature(offset_of_enum)] -struct Foo(u32, T, u8); +use std::ptr; -struct Wrapper(T); +// these types only have their field offsets taken, they're never constructed +#[allow(dead_code)] +pub struct Foo(u32, T, u8); +#[allow(dead_code)] +pub struct Wrapper(T); #[repr(transparent)] -struct TransparentWrapper(u16); +#[allow(dead_code)] +pub struct TransparentWrapper(u16); const _: () = { - // behavior of the current implementation, not guaranteed + // Behavior of the current non-randomized implementation, not guaranteed #[cfg(not(randomize_layout))] assert!(std::mem::offset_of!(Foo::, 1) == std::mem::offset_of!(Foo::>, 1)); @@ -21,10 +26,37 @@ const _: () = { assert!(std::mem::offset_of!(Foo::, 1) != std::mem::offset_of!(Foo::>, 1)); // Even transparent wrapper inner types get a different layout since associated type - // pecialization could result in the outer type behaving differently depending on the exact + // specialization could result in the outer type behaving differently depending on the exact // inner type. #[cfg(randomize_layout)] assert!( std::mem::offset_of!(Foo::, 1) != std::mem::offset_of!(Foo::, 1) ); + + // Currently all fn pointers are treated interchangably even with randomization. Not guaranteed. + // Associated type specialization could also break this. + assert!( + std::mem::offset_of!(Foo::, 1) == std::mem::offset_of!(Foo:: usize>, 1) + ); + + // But subtype coercions must always result in the same layout. + assert!( + std::mem::offset_of!(Foo::, 1) == std::mem::offset_of!(Foo::, 1) + ); + + // Randomization must uphold NPO guarantees + assert!(std::mem::offset_of!(Option::<&usize>, Some.0) == 0); + assert!(std::mem::offset_of!(Result::<&usize, ()>, Ok.0) == 0); }; + +#[allow(dead_code)] +struct Unsizable(usize, T); + +fn main() { + // offset_of doesn't let us probe the unsized field, check at runtime. + let x = &Unsizable::<[u32; 4]>(0, [0; 4]); + let y: &Unsizable::<[u32]> = x; + + // type coercion must not change the layout. + assert_eq!(ptr::from_ref(&x.1).addr(), ptr::from_ref(&y.1).addr()); +} From 7c91f898ba9d89f0ba630b93d38b1c5b9b8b006b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 9 Jan 2025 21:40:14 -0800 Subject: [PATCH 171/189] Fix typo in `#[coroutine]` gating error --- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- tests/ui/coroutine/gen_block.e2024.stderr | 4 ++-- tests/ui/coroutine/gen_block.none.stderr | 4 ++-- tests/ui/coroutine/gen_block.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5421517046d86..3c3bbc8c31d86 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -572,7 +572,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // `#[coroutine]` attribute to be applied to closures to make them coroutines instead gated!( coroutine, Normal, template!(Word), ErrorFollowing, - EncodeCrossCrate::No, coroutines, experimental!(coroutines) + EncodeCrossCrate::No, coroutines, experimental!(coroutine) ), // RFC 3543 diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr index 322259cf2f84f..0491bdbc2e17a 100644 --- a/tests/ui/coroutine/gen_block.e2024.stderr +++ b/tests/ui/coroutine/gen_block.e2024.stderr @@ -1,4 +1,4 @@ -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:20:13 | LL | let _ = #[coroutine] || yield true; @@ -8,7 +8,7 @@ LL | let _ = #[coroutine] || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:24:13 | LL | let _ = #[coroutine] || {}; diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr index 15123a49e4855..43437793005a5 100644 --- a/tests/ui/coroutine/gen_block.none.stderr +++ b/tests/ui/coroutine/gen_block.none.stderr @@ -44,7 +44,7 @@ LL | let _ = #[coroutine] || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:20:13 | LL | let _ = #[coroutine] || yield true; @@ -54,7 +54,7 @@ LL | let _ = #[coroutine] || yield true; = help: add `#![feature(coroutines)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: the `#[coroutines]` attribute is an experimental feature +error[E0658]: the `#[coroutine]` attribute is an experimental feature --> $DIR/gen_block.rs:24:13 | LL | let _ = #[coroutine] || {}; diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs index 6734de3b667d2..4494d654eeb62 100644 --- a/tests/ui/coroutine/gen_block.rs +++ b/tests/ui/coroutine/gen_block.rs @@ -18,9 +18,9 @@ fn main() { //~^^ ERROR `yield` can only be used in let _ = #[coroutine] || yield true; //[none]~ ERROR yield syntax is experimental - //~^ ERROR `#[coroutines]` attribute is an experimental feature + //~^ ERROR `#[coroutine]` attribute is an experimental feature //~^^ ERROR yield syntax is experimental let _ = #[coroutine] || {}; - //~^ ERROR `#[coroutines]` attribute is an experimental feature + //~^ ERROR `#[coroutine]` attribute is an experimental feature } From 1c619373f93cef69cba288fdd8725adf029efecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 10 Jan 2025 07:08:28 +0100 Subject: [PATCH 172/189] remove more redundant into() conversions --- compiler/rustc_hir_analysis/src/collect/predicates_of.rs | 2 +- compiler/rustc_mir_transform/src/coverage/mappings.rs | 5 ++--- .../rustc_mir_transform/src/lint_tail_expr_drop_order.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 0c19e2e4c5184..1569c0963c84b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1036,7 +1036,7 @@ pub(super) fn const_conditions<'tcx>( icx.lowerer().lower_bounds( tcx.types.self_param, - supertraits.into_iter(), + supertraits, &mut bounds, ty::List::empty(), PredicateFilter::ConstIfConst, diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 4185b3f4d4d85..5bd20e00eb68c 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -367,9 +367,8 @@ fn calc_test_vectors_index(conditions: &mut Vec) -> usize { }) .collect::>(); - let mut queue = std::collections::VecDeque::from_iter( - next_conditions.swap_remove(&ConditionId::START).into_iter(), - ); + let mut queue = + std::collections::VecDeque::from_iter(next_conditions.swap_remove(&ConditionId::START)); num_paths_stats[ConditionId::START] = 1; let mut decision_end_nodes = Vec::new(); while let Some(branch) = queue.pop_front() { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 6590702118c7f..50d10883d2cad 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -691,7 +691,7 @@ impl Subdiagnostic for LocalLabel<'_> { for dtor in self.destructors { dtor.add_to_diag_with(diag, f); } - let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into()); + let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue); diag.span_label(self.span, msg); } } From aec51564a55375e7fcf52bfccef226381f220bb5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 8 Jan 2025 14:21:40 +0000 Subject: [PATCH 173/189] Add regression test for option initialization --- tests/codegen/slice-init.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs index 8126bf84618aa..a01b432add63a 100644 --- a/tests/codegen/slice-init.rs +++ b/tests/codegen/slice-init.rs @@ -63,6 +63,34 @@ pub fn nonzero_integer_array() { opaque(&x); } +const N: usize = 100; + +// FIXME: The two bytes of the u16 are the same, so we should +// just use memset, too. +// CHECK-LABEL: @u16_init_one_bytes +#[no_mangle] +pub fn u16_init_one_bytes() -> [u16; N] { + // CHECK-NOT: select + // CHECK: br + // CHECK-NOT: switch + // CHECK: icmp + // CHECK-NOT: call void @llvm.memset.p0 + [const { u16::from_be_bytes([1, 1]) }; N] +} + +// FIXME: undef bytes can just be initialized with the same value as the +// defined bytes, if the defines bytes are all the same. +// CHECK-LABEL: @option_none_init +#[no_mangle] +pub fn option_none_init() -> [Option; N] { + // CHECK-NOT: select + // CHECK: br label %repeat_loop_header{{.*}} + // CHECK-NOT: switch + // CHECK: icmp + // CHECK-NOT: call void @llvm.memset.p0 + [None; N] +} + // Use an opaque function to prevent rustc from removing useless drops. #[inline(never)] pub fn opaque(_: impl Sized) {} From 7ad45f1d2fc5b237a0f3ce128dc403eb6f618403 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 8 Jan 2025 15:00:25 +0000 Subject: [PATCH 174/189] Change repeat element check into a match --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 3b62148abb789..8ef25d4e2ffb5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -93,23 +93,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - if let OperandValue::Immediate(v) = cg_elem.val { - let start = dest.val.llval; - let size = bx.const_usize(dest.layout.size.bytes()); - - // Use llvm.memset.p0i8.* to initialize all zero arrays - if bx.cx().const_to_opt_u128(v, false) == Some(0) { - let fill = bx.cx().const_u8(0); - bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); - return; - } + match cg_elem.val { + OperandValue::Immediate(v) => { + let start = dest.val.llval; + let size = bx.const_usize(dest.layout.size.bytes()); + + // Use llvm.memset.p0i8.* to initialize all zero arrays + if bx.cx().const_to_opt_u128(v, false) == Some(0) { + let fill = bx.cx().const_u8(0); + bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); + return; + } - // Use llvm.memset.p0i8.* to initialize byte arrays - let v = bx.from_immediate(v); - if bx.cx().val_ty(v) == bx.cx().type_i8() { - bx.memset(start, v, size, dest.val.align, MemFlags::empty()); - return; + // Use llvm.memset.p0i8.* to initialize byte arrays + let v = bx.from_immediate(v); + if bx.cx().val_ty(v) == bx.cx().type_i8() { + bx.memset(start, v, size, dest.val.align, MemFlags::empty()); + return; + } } + _ => (), } let count = self From 65ea9f3eb40e113284d0142f28e061fd90191c46 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 8 Jan 2025 16:15:50 +0000 Subject: [PATCH 175/189] Pull element init into a reusable closure --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 35 ++++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 8ef25d4e2ffb5..e36e0e18d9ccd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -93,22 +93,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - match cg_elem.val { - OperandValue::Immediate(v) => { - let start = dest.val.llval; - let size = bx.const_usize(dest.layout.size.bytes()); + let try_init_all_same = |bx: &mut Bx, v| { + let start = dest.val.llval; + let size = bx.const_usize(dest.layout.size.bytes()); + + // Use llvm.memset.p0i8.* to initialize all zero arrays + if bx.cx().const_to_opt_u128(v, false) == Some(0) { + let fill = bx.cx().const_u8(0); + bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); + return true; + } - // Use llvm.memset.p0i8.* to initialize all zero arrays - if bx.cx().const_to_opt_u128(v, false) == Some(0) { - let fill = bx.cx().const_u8(0); - bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); - return; - } + // Use llvm.memset.p0i8.* to initialize byte arrays + let v = bx.from_immediate(v); + if bx.cx().val_ty(v) == bx.cx().type_i8() { + bx.memset(start, v, size, dest.val.align, MemFlags::empty()); + return true; + } + false + }; - // Use llvm.memset.p0i8.* to initialize byte arrays - let v = bx.from_immediate(v); - if bx.cx().val_ty(v) == bx.cx().type_i8() { - bx.memset(start, v, size, dest.val.align, MemFlags::empty()); + match cg_elem.val { + OperandValue::Immediate(v) => { + if try_init_all_same(bx, v) { return; } } From e39eacd2d415803ef82de3b6a314e4f2d0fbc4dc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 10 Jan 2025 08:55:32 +0000 Subject: [PATCH 176/189] Rustup to rustc 1.86.0-nightly (824759493 2025-01-09) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 1105b89fbb3ef..e4c3dd708fd98 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-01-09" +channel = "nightly-2025-01-10" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 65b01cb1823926fd4e2f2c94b206aad0220c0e1c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 8 Jan 2025 16:29:32 +0000 Subject: [PATCH 177/189] Use llvm.memset.p0i8.* to initialize all same-bytes arrays --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 14 +++++++++----- tests/codegen/slice-init.rs | 8 +++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e36e0e18d9ccd..31793641d75ed 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -97,11 +97,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let start = dest.val.llval; let size = bx.const_usize(dest.layout.size.bytes()); - // Use llvm.memset.p0i8.* to initialize all zero arrays - if bx.cx().const_to_opt_u128(v, false) == Some(0) { - let fill = bx.cx().const_u8(0); - bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); - return true; + // Use llvm.memset.p0i8.* to initialize all same byte arrays + if let Some(int) = bx.cx().const_to_opt_u128(v, false) { + let bytes = &int.to_le_bytes()[..cg_elem.layout.size.bytes_usize()]; + let first = bytes[0]; + if bytes[1..].iter().all(|&b| b == first) { + let fill = bx.cx().const_u8(first); + bx.memset(start, fill, size, dest.val.align, MemFlags::empty()); + return true; + } } // Use llvm.memset.p0i8.* to initialize byte arrays diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs index a01b432add63a..1c2dd3e887555 100644 --- a/tests/codegen/slice-init.rs +++ b/tests/codegen/slice-init.rs @@ -65,16 +65,14 @@ pub fn nonzero_integer_array() { const N: usize = 100; -// FIXME: The two bytes of the u16 are the same, so we should -// just use memset, too. // CHECK-LABEL: @u16_init_one_bytes #[no_mangle] pub fn u16_init_one_bytes() -> [u16; N] { // CHECK-NOT: select - // CHECK: br + // CHECK-NOT: br // CHECK-NOT: switch - // CHECK: icmp - // CHECK-NOT: call void @llvm.memset.p0 + // CHECK-NOT: icmp + // CHECK: call void @llvm.memset.p0 [const { u16::from_be_bytes([1, 1]) }; N] } From 4426e9a3c260e329f51c94e2b231f72574271f0b Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 10 Jan 2025 18:48:48 +0100 Subject: [PATCH 178/189] alloc: remove unsound `IsZero` for raw pointers Fixes #135338 --- library/alloc/src/vec/is_zero.rs | 15 ++------------- library/alloc/tests/vec.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index ba57d940d8c99..a3ddd6f6e230e 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -40,19 +40,8 @@ impl_is_zero!(char, |x| x == '\0'); impl_is_zero!(f32, |x: f32| x.to_bits() == 0); impl_is_zero!(f64, |x: f64| x.to_bits() == 0); -unsafe impl IsZero for *const T { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } -} - -unsafe impl IsZero for *mut T { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } -} +// `IsZero` cannot be soundly implemented for pointers because of provenance +// (see #135338). unsafe impl IsZero for [T; N] { #[inline] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 2e654d3d1ff1e..b24daec2968e0 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -2742,3 +2742,13 @@ fn max_swap_remove() { let mut v = vec![0]; v.swap_remove(usize::MAX); } + +// Regression test for #135338 +#[test] +fn vec_null_ptr_roundtrip() { + let ptr = std::ptr::from_ref(&42); + let zero = ptr.with_addr(0); + let roundtripped = vec![zero; 1].pop().unwrap(); + let new = roundtripped.with_addr(ptr.addr()); + unsafe { new.read() }; +} From f86169a58f212b174a01aa721545df009e96bfda Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 23 Sep 2024 18:46:23 +0100 Subject: [PATCH 179/189] mir_transform: implement forced inlining Adds `#[rustc_force_inline]` which is similar to always inlining but reports an error if the inlining was not possible, and which always attempts to inline annotated items, regardless of optimisation levels. It can only be applied to free functions to guarantee that the MIR inliner will be able to resolve calls. --- .../src/attributes.rs | 16 + compiler/rustc_codegen_gcc/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 4 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 63 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 + compiler/rustc_hir_typeck/src/coercion.rs | 19 +- compiler/rustc_middle/src/mir/mono.rs | 7 +- compiler/rustc_middle/src/ty/error.rs | 3 + compiler/rustc_mir_transform/messages.ftl | 11 + .../src/cross_crate_inline.rs | 7 +- compiler/rustc_mir_transform/src/errors.rs | 28 +- compiler/rustc_mir_transform/src/inline.rs | 1498 ++++++++++------- compiler/rustc_mir_transform/src/lib.rs | 8 +- .../rustc_mir_transform/src/pass_manager.rs | 10 + compiler/rustc_mir_transform/src/validate.rs | 24 +- compiler/rustc_monomorphize/src/collector.rs | 9 + compiler/rustc_passes/messages.ftl | 8 + compiler/rustc_passes/src/check_attr.rs | 42 +- compiler/rustc_passes/src/errors.rs | 18 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_trait_selection/messages.ftl | 4 +- .../src/error_reporting/infer/mod.rs | 7 +- compiler/rustc_trait_selection/src/errors.rs | 11 +- compiler/rustc_type_ir/src/error.rs | 4 + ...forced.caller.ForceInline.panic-abort.diff | 21 + ...orced.caller.ForceInline.panic-unwind.diff | 21 + tests/mir-opt/inline/forced.rs | 13 + ..._async.caller.ForceInline.panic-abort.diff | 12 + ...async.caller.ForceInline.panic-unwind.diff | 12 + tests/mir-opt/inline/forced_async.rs | 14 + ...r-{closure#0}.ForceInline.panic-abort.diff | 21 + ...-{closure#0}.ForceInline.panic-unwind.diff | 21 + tests/mir-opt/inline/forced_closure.rs | 15 + tests/ui/force-inlining/auxiliary/callees.rs | 10 + tests/ui/force-inlining/cast.rs | 25 + tests/ui/force-inlining/cast.stderr | 40 + tests/ui/force-inlining/cross-crate.rs | 13 + tests/ui/force-inlining/deny-async.rs | 25 + tests/ui/force-inlining/deny-async.stderr | 19 + tests/ui/force-inlining/deny-closure.rs | 26 + tests/ui/force-inlining/deny-closure.stderr | 28 + tests/ui/force-inlining/deny.rs | 24 + tests/ui/force-inlining/deny.stderr | 19 + tests/ui/force-inlining/gate.rs | 12 + tests/ui/force-inlining/gate.stderr | 21 + tests/ui/force-inlining/invalid.rs | 164 ++ tests/ui/force-inlining/invalid.stderr | 377 +++++ 47 files changed, 2091 insertions(+), 670 deletions(-) create mode 100644 tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced.rs create mode 100644 tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_async.rs create mode 100644 tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_closure.rs create mode 100644 tests/ui/force-inlining/auxiliary/callees.rs create mode 100644 tests/ui/force-inlining/cast.rs create mode 100644 tests/ui/force-inlining/cast.stderr create mode 100644 tests/ui/force-inlining/cross-crate.rs create mode 100644 tests/ui/force-inlining/deny-async.rs create mode 100644 tests/ui/force-inlining/deny-async.stderr create mode 100644 tests/ui/force-inlining/deny-closure.rs create mode 100644 tests/ui/force-inlining/deny-closure.stderr create mode 100644 tests/ui/force-inlining/deny.rs create mode 100644 tests/ui/force-inlining/deny.stderr create mode 100644 tests/ui/force-inlining/gate.rs create mode 100644 tests/ui/force-inlining/gate.stderr create mode 100644 tests/ui/force-inlining/invalid.rs create mode 100644 tests/ui/force-inlining/invalid.stderr diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 8986bec57de76..def6b16ee8ae3 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -11,6 +11,22 @@ pub enum InlineAttr { Hint, Always, Never, + /// `#[rustc_force_inline]` forces inlining to happen in the MIR inliner - it reports an error + /// if the inlining cannot happen. It is limited to only free functions so that the calls + /// can always be resolved. + Force { + attr_span: Span, + reason: Option, + }, +} + +impl InlineAttr { + pub fn always(&self) -> bool { + match self { + InlineAttr::Always | InlineAttr::Force { .. } => true, + InlineAttr::None | InlineAttr::Hint | InlineAttr::Never => false, + } + } } #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)] diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 028a5ab5f716b..69b04dd579693 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -20,7 +20,7 @@ fn inline_attr<'gcc, 'tcx>( ) -> Option> { match inline { InlineAttr::Hint => Some(FnAttribute::Inline), - InlineAttr::Always => Some(FnAttribute::AlwaysInline), + InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline), InlineAttr::Never => { if cx.sess().target.arch != "amdgpu" { Some(FnAttribute::NoInline) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index f8454fd9960b6..0250064e55f1f 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -37,7 +37,9 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll } match inline { InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)), - InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)), + InlineAttr::Always | InlineAttr::Force { .. } => { + Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)) + } InlineAttr::Never => { if cx.sess().target.arch != "amdgpu" { Some(AttributeKind::NoInline.create_attr(cx.llcx)) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index cdb72aba36fa0..d8f62d543ad84 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -18,6 +18,7 @@ use rustc_session::parse::feature_err; use rustc_session::{Session, lint}; use rustc_span::{Ident, Span, sym}; use rustc_target::spec::{SanitizerSet, abi}; +use tracing::debug; use crate::errors; use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr}; @@ -522,26 +523,36 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if !attr.has_name(sym::inline) { - return ia; - } - if attr.is_word() { - InlineAttr::Hint - } else if let Some(ref items) = attr.meta_item_list() { - inline_span = Some(attr.span); - if items.len() != 1 { - struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); - InlineAttr::None - } else if list_contains_name(items, sym::always) { - InlineAttr::Always - } else if list_contains_name(items, sym::never) { - InlineAttr::Never - } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); + if attr.has_name(sym::inline) { + if attr.is_word() { + InlineAttr::Hint + } else if let Some(ref items) = attr.meta_item_list() { + inline_span = Some(attr.span); + if items.len() != 1 { + struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); + InlineAttr::None + } else if list_contains_name(items, sym::always) { + InlineAttr::Always + } else if list_contains_name(items, sym::never) { + InlineAttr::Never + } else { + struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") + .with_help("valid inline arguments are `always` and `never`") + .emit(); - InlineAttr::None + InlineAttr::None + } + } else { + ia + } + } else if attr.has_name(sym::rustc_force_inline) && tcx.features().rustc_attrs() { + if attr.is_word() { + InlineAttr::Force { attr_span: attr.span, reason: None } + } else if let Some(val) = attr.value_str() { + InlineAttr::Force { attr_span: attr.span, reason: Some(val) } + } else { + debug!("`rustc_force_inline` not checked by attribute validation"); + ia } } else { ia @@ -596,7 +607,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. if tcx.features().target_feature_11() && tcx.is_closure_like(did.to_def_id()) - && codegen_fn_attrs.inline != InlineAttr::Always + && !codegen_fn_attrs.inline.always() { let owner_id = tcx.parent(did.to_def_id()); if tcx.def_kind(owner_id).has_codegen_attrs() { @@ -606,11 +617,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - // If a function uses #[target_feature] it can't be inlined into general + // If a function uses `#[target_feature]` it can't be inlined into general // purpose functions as they wouldn't have the right target features - // enabled. For that reason we also forbid #[inline(always)] as it can't be + // enabled. For that reason we also forbid `#[inline(always)]` as it can't be // respected. - if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always + // + // `#[rustc_force_inline]` doesn't need to be prohibited here, that + // is implemented entirely in rustc can attempt to inline and error if it cannot. + if !codegen_fn_attrs.target_features.is_empty() + && matches!(codegen_fn_attrs.inline, InlineAttr::Always) { if let Some(span) = inline_span { tcx.dcx().span_err( @@ -621,7 +636,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always { + if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() { if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { let hir_id = tcx.local_def_id_to_hir_id(did); tcx.node_span_lint( diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3c3bbc8c31d86..c28a4360f6f91 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1019,6 +1019,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" ), + rustc_attr!( + rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, + "#![rustc_force_inline] forces a free function to be inlined" + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bd26be11279ee..9ebc7a4657e84 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -38,6 +38,7 @@ use std::ops::Deref; use rustc_abi::ExternAbi; +use rustc_attr_parsing::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; use rustc_hir as hir; @@ -926,8 +927,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::IntrinsicCast); } - // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396). + let fn_attrs = self.tcx.codegen_fn_attrs(def_id); + if matches!(fn_attrs.inline, InlineAttr::Force { .. }) { + return Err(TypeError::ForceInlineCast); + } + // Safe `#[target_feature]` functions are not assignable to safe fn pointers + // (RFC 2396). if b_hdr.safety.is_safe() && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() { @@ -1197,6 +1203,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ok(prev_ty); } + let is_force_inline = |ty: Ty<'tcx>| { + if let ty::FnDef(did, _) = ty.kind() { + matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. }) + } else { + false + } + }; + if is_force_inline(prev_ty) || is_force_inline(new_ty) { + return Err(TypeError::ForceInlineCast); + } + // Special-case that coercion alone cannot handle: // Function items or non-capturing closures of differing IDs or GenericArgs. let (a_sig, b_sig) = { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 27168b2a9f246..111c3b6956a24 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -132,9 +132,10 @@ impl<'tcx> MonoItem<'tcx> { // creating one copy of this `#[inline]` function which may // conflict with upstream crates as it could be an exported // symbol. - match tcx.codegen_fn_attrs(instance.def_id()).inline { - InlineAttr::Always => InstantiationMode::LocalCopy, - _ => InstantiationMode::GloballyShared { may_conflict: true }, + if tcx.codegen_fn_attrs(instance.def_id()).inline.always() { + InstantiationMode::LocalCopy + } else { + InstantiationMode::GloballyShared { may_conflict: true } } } MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 714094db0530f..35fbaa99569c9 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -109,6 +109,9 @@ impl<'tcx> TypeError<'tcx> { TypeError::ConstMismatch(ref values) => { format!("expected `{}`, found `{}`", values.expected, values.found).into() } + TypeError::ForceInlineCast => { + "cannot coerce functions which must be inlined to function pointers".into() + } TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), TypeError::TargetFeatureCast(_) => { "cannot coerce functions with `#[target_feature]` to safe function pointers".into() diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index d00bfc66a6a57..b0c023cca8242 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -19,6 +19,17 @@ mir_transform_ffi_unwind_call = call to {$foreign -> mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer .suggestion = cast `{$ident}` to obtain a function pointer +mir_transform_force_inline = + `{$callee}` could not be inlined into `{$caller}` but is required to be inlined + .call = ...`{$callee}` called here + .attr = inlining due to this annotation + .caller = within `{$caller}`... + .callee = `{$callee}` defined here + .note = could not be inlined due to: {$reason} + +mir_transform_force_inline_justification = + `{$callee}` is required to be inlined to: {$sym} + mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be .label = the value is held across this suspend point .note = {$reason} diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index e1f1dd83f0df4..8fce856687cb8 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -46,7 +46,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // #[inline(never)] to force code generation. match codegen_fn_attrs.inline { InlineAttr::Never => return false, - InlineAttr::Hint | InlineAttr::Always => return true, + InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. } => return true, _ => {} } @@ -69,8 +69,9 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // Don't do any inference if codegen optimizations are disabled and also MIR inlining is not // enabled. This ensures that we do inference even if someone only passes -Zinline-mir, // which is less confusing than having to also enable -Copt-level=1. - if matches!(tcx.sess.opts.optimize, OptLevel::No) && !pm::should_run_pass(tcx, &inline::Inline) - { + let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline) + || inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id()); + if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run { return false; } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 2d9eeddea2e22..015633d145f15 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -4,8 +4,8 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::AssertKind; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{self, Lint}; -use rustc_span::Span; use rustc_span::def_id::DefId; +use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; @@ -142,3 +142,29 @@ pub(crate) struct MustNotSuspendReason { #[note(mir_transform_note2)] #[help] pub(crate) struct UndefinedTransmute; + +#[derive(Diagnostic)] +#[diag(mir_transform_force_inline)] +#[note] +pub(crate) struct ForceInlineFailure { + #[label(mir_transform_caller)] + pub caller_span: Span, + #[label(mir_transform_callee)] + pub callee_span: Span, + #[label(mir_transform_attr)] + pub attr_span: Span, + #[primary_span] + #[label(mir_transform_call)] + pub call_span: Span, + pub callee: String, + pub caller: String, + pub reason: &'static str, + #[subdiagnostic] + pub justification: Option, +} + +#[derive(Subdiagnostic)] +#[note(mir_transform_force_inline_justification)] +pub(crate) struct ForceInlineJustification { + pub sym: Symbol, +} diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 339acbad6b904..a5a4b5987f567 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -6,7 +6,7 @@ use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; use rustc_attr_parsing::InlineAttr; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::Idx; use rustc_index::bit_set::BitSet; use rustc_middle::bug; @@ -29,10 +29,6 @@ pub(crate) mod cycle; const TOP_DOWN_DEPTH_LIMIT: usize = 5; -// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden -// by custom rustc drivers, running all the steps by themselves. See #114628. -pub struct Inline; - #[derive(Clone, Debug)] struct CallSite<'tcx> { callee: Instance<'tcx>, @@ -41,14 +37,12 @@ struct CallSite<'tcx> { source_info: SourceInfo, } +// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden +// by custom rustc drivers, running all the steps by themselves. See #114628. +pub struct Inline; + impl<'tcx> crate::MirPass<'tcx> for Inline { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined - // MIR correctly when Modified Condition/Decision Coverage is enabled. - if sess.instrument_coverage_mcdc() { - return false; - } - if let Some(enabled) = sess.opts.unstable_opts.inline_mir { return enabled; } @@ -67,7 +61,7 @@ impl<'tcx> crate::MirPass<'tcx> for Inline { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id())); let _guard = span.enter(); - if inline(tcx, body) { + if inline::>(tcx, body) { debug!("running simplify cfg on {:?}", body.source); simplify_cfg(body); deref_finder(tcx, body); @@ -75,47 +69,84 @@ impl<'tcx> crate::MirPass<'tcx> for Inline { } } -fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { - let def_id = body.source.def_id().expect_local(); +pub struct ForceInline; - // Only do inlining into fn bodies. - if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() { - return false; +impl ForceInline { + pub fn should_run_pass_for_callee<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + matches!(tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. }) } - if body.source.promoted.is_some() { - return false; +} + +impl<'tcx> crate::MirPass<'tcx> for ForceInline { + fn is_enabled(&self, _: &rustc_session::Session) -> bool { + true } - // Avoid inlining into coroutines, since their `optimized_mir` is used for layout computation, - // which can create a cycle, even when no attempt is made to inline the function in the other - // direction. - if body.coroutine.is_some() { - return false; + + fn can_be_overridden(&self) -> bool { + false } - let typing_env = body.typing_env(tcx); - let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let span = trace_span!("force_inline", body = %tcx.def_path_str(body.source.def_id())); + let _guard = span.enter(); + if inline::>(tcx, body) { + debug!("running simplify cfg on {:?}", body.source); + simplify_cfg(body); + deref_finder(tcx, body); + } + } +} - let mut this = Inliner { - tcx, - typing_env, - codegen_fn_attrs, - history: Vec::new(), - changed: false, - caller_is_inline_forwarder: matches!( - codegen_fn_attrs.inline, - InlineAttr::Hint | InlineAttr::Always - ) && body_is_forwarder(body), - }; - let blocks = START_BLOCK..body.basic_blocks.next_index(); - this.process_blocks(body, blocks); - this.changed +trait Inliner<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) -> Self; + + fn tcx(&self) -> TyCtxt<'tcx>; + fn typing_env(&self) -> ty::TypingEnv<'tcx>; + fn history(&self) -> &[DefId]; + fn caller_def_id(&self) -> LocalDefId; + + /// Has the caller body been changed? + fn changed(self) -> bool; + + /// Should inlining happen for a given callee? + fn should_inline_for_callee(&self, def_id: DefId) -> bool; + + fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool; + + /// Returns inlining decision that is based on the examination of callee MIR body. + /// Assumes that codegen attributes have been checked for compatibility already. + fn check_callee_mir_body( + &self, + callsite: &CallSite<'tcx>, + callee_body: &Body<'tcx>, + callee_attrs: &CodegenFnAttrs, + cross_crate_inlinable: bool, + ) -> Result<(), &'static str>; + + // How many callsites in a body are we allowed to inline? We need to limit this in order + // to prevent super-linear growth in MIR size. + fn inline_limit_for_block(&self) -> Option; + + /// Called when inlining succeeds. + fn on_inline_success( + &mut self, + callsite: &CallSite<'tcx>, + caller_body: &mut Body<'tcx>, + new_blocks: std::ops::Range, + ); + + /// Called when inlining failed or was not performed. + fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str); + + /// Called when the inline limit for a body is reached. + fn on_inline_limit_reached(&self) -> bool; } -struct Inliner<'tcx> { +struct ForceInliner<'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - /// Caller codegen attributes. - codegen_fn_attrs: &'tcx CodegenFnAttrs, + /// `DefId` of caller. + def_id: LocalDefId, /// Stack of inlined instances. /// We only check the `DefId` and not the args because we want to /// avoid inlining cases of polymorphic recursion. @@ -124,366 +155,190 @@ struct Inliner<'tcx> { history: Vec, /// Indicates that the caller body has been modified. changed: bool, - /// Indicates that the caller is #[inline] and just calls another function, - /// and thus we can inline less into it as it'll be inlined itself. - caller_is_inline_forwarder: bool, } -impl<'tcx> Inliner<'tcx> { - fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range) { - // How many callsites in this body are we allowed to inline? We need to limit this in order - // to prevent super-linear growth in MIR size - let inline_limit = match self.history.len() { - 0 => usize::MAX, - 1..=TOP_DOWN_DEPTH_LIMIT => 1, - _ => return, - }; - let mut inlined_count = 0; - for bb in blocks { - let bb_data = &caller_body[bb]; - if bb_data.is_cleanup { - continue; - } - - let Some(callsite) = self.resolve_callsite(caller_body, bb, bb_data) else { - continue; - }; - - let span = trace_span!("process_blocks", %callsite.callee, ?bb); - let _guard = span.enter(); - - match self.try_inlining(caller_body, &callsite) { - Err(reason) => { - debug!("not-inlined {} [{}]", callsite.callee, reason); - } - Ok(new_blocks) => { - debug!("inlined {}", callsite.callee); - self.changed = true; - - self.history.push(callsite.callee.def_id()); - self.process_blocks(caller_body, new_blocks); - self.history.pop(); - - inlined_count += 1; - if inlined_count == inline_limit { - debug!("inline count reached"); - return; - } - } - } - } +impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) -> Self { + Self { tcx, typing_env: body.typing_env(tcx), def_id, history: Vec::new(), changed: false } } - /// Attempts to inline a callsite into the caller body. When successful returns basic blocks - /// containing the inlined body. Otherwise returns an error describing why inlining didn't take - /// place. - fn try_inlining( - &self, - caller_body: &mut Body<'tcx>, - callsite: &CallSite<'tcx>, - ) -> Result, &'static str> { - self.check_mir_is_available(caller_body, callsite.callee)?; - - let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); - let cross_crate_inlinable = self.tcx.cross_crate_inlinable(callsite.callee.def_id()); - self.check_codegen_attributes(callsite, callee_attrs, cross_crate_inlinable)?; - - // Intrinsic fallback bodies are automatically made cross-crate inlineable, - // but at this stage we don't know whether codegen knows the intrinsic, - // so just conservatively don't inline it. This also ensures that we do not - // accidentally inline the body of an intrinsic that *must* be overridden. - if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_intrinsic) { - return Err("Callee is an intrinsic, do not inline fallback bodies"); - } - - let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); - let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; - let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; - for arg in args { - if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.typing_env) - { - // We do not allow inlining functions with unsized params. Inlining these functions - // could create unsized locals, which are unsound and being phased out. - return Err("Call has unsized argument"); - } - } - - let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?; - self.check_mir_body(callsite, callee_body, callee_attrs, cross_crate_inlinable)?; - - let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( - self.tcx, - self.typing_env, - ty::EarlyBinder::bind(callee_body.clone()), - ) else { - return Err("failed to normalize callee body"); - }; - - // Normally, this shouldn't be required, but trait normalization failure can create a - // validation ICE. - if !validate_types(self.tcx, self.typing_env, &callee_body, &caller_body).is_empty() { - return Err("failed to validate callee body"); - } - - // Check call signature compatibility. - // Normally, this shouldn't be required, but trait normalization failure can create a - // validation ICE. - let output_type = callee_body.return_ty(); - if !util::sub_types(self.tcx, self.typing_env, output_type, destination_ty) { - trace!(?output_type, ?destination_ty); - return Err("failed to normalize return type"); - } - if callsite.fn_sig.abi() == ExternAbi::RustCall { - // FIXME: Don't inline user-written `extern "rust-call"` functions, - // since this is generally perf-negative on rustc, and we hope that - // LLVM will inline these functions instead. - if callee_body.spread_arg.is_some() { - return Err("do not inline user-written rust-call functions"); - } + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } - let (self_arg, arg_tuple) = match &args[..] { - [arg_tuple] => (None, arg_tuple), - [self_arg, arg_tuple] => (Some(self_arg), arg_tuple), - _ => bug!("Expected `rust-call` to have 1 or 2 args"), - }; + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env + } - let self_arg_ty = - self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, self.tcx)); + fn history(&self) -> &[DefId] { + &self.history + } - let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, self.tcx); - let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else { - bug!("Closure arguments are not passed as a tuple"); - }; + fn caller_def_id(&self) -> LocalDefId { + self.def_id + } - for (arg_ty, input) in - 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::sub_types(self.tcx, self.typing_env, input_type, arg_ty) { - trace!(?arg_ty, ?input_type); - return Err("failed to normalize tuple argument type"); - } - } - } else { - 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::sub_types(self.tcx, self.typing_env, input_type, arg_ty) { - trace!(?arg_ty, ?input_type); - return Err("failed to normalize argument type"); - } - } - } + fn changed(self) -> bool { + self.changed + } - let old_blocks = caller_body.basic_blocks.next_index(); - self.inline_call(caller_body, callsite, callee_body); - let new_blocks = old_blocks..caller_body.basic_blocks.next_index(); + fn should_inline_for_callee(&self, def_id: DefId) -> bool { + ForceInline::should_run_pass_for_callee(self.tcx(), def_id) + } - Ok(new_blocks) + fn check_caller_mir_body(&self, _: &Body<'tcx>) -> bool { + true } - fn check_mir_is_available( + #[instrument(level = "debug", skip(self, callee_body))] + fn check_callee_mir_body( &self, - caller_body: &Body<'tcx>, - callee: Instance<'tcx>, + _: &CallSite<'tcx>, + callee_body: &Body<'tcx>, + _: &CodegenFnAttrs, + _: bool, ) -> Result<(), &'static str> { - let caller_def_id = caller_body.source.def_id(); - let callee_def_id = callee.def_id(); - if callee_def_id == caller_def_id { - return Err("self-recursion"); - } - - match callee.def { - InstanceKind::Item(_) => { - // If there is no MIR available (either because it was not in metadata or - // because it has no MIR because it's an extern function), then the inliner - // won't cause cycles on this. - if !self.tcx.is_mir_available(callee_def_id) { - return Err("item MIR unavailable"); - } - } - // These have no own callable MIR. - InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { - return Err("instance without MIR (intrinsic / virtual)"); - } - - // FIXME(#127030): `ConstParamHasTy` has bad interactions with - // the drop shim builder, which does not evaluate predicates in - // the correct param-env for types being dropped. Stall resolving - // the MIR for this instance until all of its const params are - // substituted. - InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { - return Err("still needs substitution"); - } - - // This cannot result in an immediate cycle since the callee MIR is a shim, which does - // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we - // do not need to catch this here, we can wait until the inliner decides to continue - // inlining a second time. - InstanceKind::VTableShim(_) - | InstanceKind::ReifyShim(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::CloneShim(..) - | InstanceKind::ThreadLocalShim(..) - | InstanceKind::FnPtrAddrShim(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => return Ok(()), - } + if let Some(_) = callee_body.tainted_by_errors { Err("body has errors") } else { Ok(()) } + } - if self.tcx.is_constructor(callee_def_id) { - trace!("constructors always have MIR"); - // Constructor functions cannot cause a query cycle. - return Ok(()); - } + fn inline_limit_for_block(&self) -> Option { + Some(usize::MAX) + } - if callee_def_id.is_local() { - // If we know for sure that the function we're calling will itself try to - // call us, then we avoid inlining that function. - if self.tcx.mir_callgraph_reachable((callee, caller_def_id.expect_local())) { - return Err("caller might be reachable from callee (query cycle avoidance)"); - } + fn on_inline_success( + &mut self, + callsite: &CallSite<'tcx>, + caller_body: &mut Body<'tcx>, + new_blocks: std::ops::Range, + ) { + self.changed = true; - Ok(()) - } else { - // This cannot result in an immediate cycle since the callee MIR is from another crate - // and is already optimized. Any subsequent inlining may cause cycles, but we do - // not need to catch this here, we can wait until the inliner decides to continue - // inlining a second time. - trace!("functions from other crates always have MIR"); - Ok(()) - } + self.history.push(callsite.callee.def_id()); + process_blocks(self, caller_body, new_blocks); + self.history.pop(); } - fn resolve_callsite( - &self, - caller_body: &Body<'tcx>, - bb: BasicBlock, - bb_data: &BasicBlockData<'tcx>, - ) -> Option> { - // Only consider direct calls to functions - let terminator = bb_data.terminator(); - - // FIXME(explicit_tail_calls): figure out if we can inline tail calls - if let TerminatorKind::Call { ref func, fn_span, .. } = terminator.kind { - let func_ty = func.ty(caller_body, self.tcx); - if let ty::FnDef(def_id, args) = *func_ty.kind() { - // To resolve an instance its args have to be fully normalized. - let args = self.tcx.try_normalize_erasing_regions(self.typing_env, args).ok()?; - let callee = Instance::try_resolve(self.tcx, self.typing_env, def_id, args) - .ok() - .flatten()?; - - if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { - return None; - } - - if self.history.contains(&callee.def_id()) { - return None; - } + fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str) { + let tcx = self.tcx(); + let InlineAttr::Force { attr_span, reason: justification } = + tcx.codegen_fn_attrs(callsite.callee.def_id()).inline + else { + bug!("called on item without required inlining"); + }; - let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args); + let call_span = callsite.source_info.span; + tcx.dcx().emit_err(crate::errors::ForceInlineFailure { + call_span, + attr_span, + caller_span: tcx.def_span(self.def_id), + caller: tcx.def_path_str(self.def_id), + callee_span: tcx.def_span(callsite.callee.def_id()), + callee: tcx.def_path_str(callsite.callee.def_id()), + reason, + justification: justification.map(|sym| crate::errors::ForceInlineJustification { sym }), + }); + } - // Additionally, check that the body that we're inlining actually agrees - // with the ABI of the trait that the item comes from. - if let InstanceKind::Item(instance_def_id) = callee.def - && self.tcx.def_kind(instance_def_id) == DefKind::AssocFn - && let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder() - && instance_fn_sig.abi() != fn_sig.abi() - { - return None; - } + fn on_inline_limit_reached(&self) -> bool { + false + } +} - let source_info = SourceInfo { span: fn_span, ..terminator.source_info }; +struct NormalInliner<'tcx> { + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + /// `DefId` of caller. + def_id: LocalDefId, + /// Stack of inlined instances. + /// We only check the `DefId` and not the args because we want to + /// avoid inlining cases of polymorphic recursion. + /// The number of `DefId`s is finite, so checking history is enough + /// to ensure that we do not loop endlessly while inlining. + history: Vec, + /// Indicates that the caller body has been modified. + changed: bool, + /// Indicates that the caller is #[inline] and just calls another function, + /// and thus we can inline less into it as it'll be inlined itself. + caller_is_inline_forwarder: bool, +} - return Some(CallSite { callee, fn_sig, block: bb, source_info }); - } +impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) -> Self { + let typing_env = body.typing_env(tcx); + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); + + Self { + tcx, + typing_env, + def_id, + history: Vec::new(), + changed: false, + caller_is_inline_forwarder: matches!( + codegen_fn_attrs.inline, + InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. } + ) && body_is_forwarder(body), } - - None } - /// Returns an error if inlining is not possible based on codegen attributes alone. A success - /// indicates that inlining decision should be based on other criteria. - fn check_codegen_attributes( - &self, - callsite: &CallSite<'tcx>, - callee_attrs: &CodegenFnAttrs, - cross_crate_inlinable: bool, - ) -> Result<(), &'static str> { - if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_no_mir_inline) { - return Err("#[rustc_no_mir_inline]"); - } + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } - if let InlineAttr::Never = callee_attrs.inline { - return Err("never inline hint"); - } + fn caller_def_id(&self) -> LocalDefId { + self.def_id + } - // Reachability pass defines which functions are eligible for inlining. Generally inlining - // other functions is incorrect because they could reference symbols that aren't exported. - let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); - if !is_generic && !cross_crate_inlinable { - return Err("not exported"); - } + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env + } - if callsite.fn_sig.c_variadic() { - return Err("C variadic"); - } + fn history(&self) -> &[DefId] { + &self.history + } - if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) { - return Err("cold"); - } + fn changed(self) -> bool { + self.changed + } - if callee_attrs.no_sanitize != self.codegen_fn_attrs.no_sanitize { - return Err("incompatible sanitizer set"); - } + fn should_inline_for_callee(&self, _: DefId) -> bool { + true + } - // Two functions are compatible if the callee has no attribute (meaning - // that it's codegen agnostic), or sets an attribute that is identical - // to this function's attribute. - if callee_attrs.instruction_set.is_some() - && callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set - { - return Err("incompatible instruction set"); + fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool { + if body.source.promoted.is_some() { + return false; } - let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name); - let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name); - if callee_feature_names.ne(this_feature_names) { - // In general it is not correct to inline a callee with target features that are a - // subset of the caller. This is because the callee might contain calls, and the ABI of - // those calls depends on the target features of the surrounding function. By moving a - // `Call` terminator from one MIR body to another with more target features, we might - // change the ABI of that call! - return Err("incompatible target features"); + // Avoid inlining into coroutines, since their `optimized_mir` is used for layout computation, + // which can create a cycle, even when no attempt is made to inline the function in the other + // direction. + if body.coroutine.is_some() { + return false; } - Ok(()) + true } - /// Returns inlining decision that is based on the examination of callee MIR body. - /// Assumes that codegen attributes have been checked for compatibility already. #[instrument(level = "debug", skip(self, callee_body))] - fn check_mir_body( + fn check_callee_mir_body( &self, callsite: &CallSite<'tcx>, callee_body: &Body<'tcx>, callee_attrs: &CodegenFnAttrs, cross_crate_inlinable: bool, ) -> Result<(), &'static str> { - let tcx = self.tcx; + let tcx = self.tcx(); if let Some(_) = callee_body.tainted_by_errors { - return Err("Body is tainted"); + return Err("body has errors"); } let mut threshold = if self.caller_is_inline_forwarder { - self.tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30) + tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30) } else if cross_crate_inlinable { - self.tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) + tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) } else { - self.tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50) + tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50) }; // Give a bonus functions with a small number of blocks, @@ -497,7 +352,7 @@ impl<'tcx> Inliner<'tcx> { // FIXME: Give a bonus to functions with only a single caller let mut checker = - CostChecker::new(self.tcx, self.typing_env, Some(callsite.callee), callee_body); + CostChecker::new(tcx, self.typing_env(), Some(callsite.callee), callee_body); checker.add_function_level_costs(); @@ -513,20 +368,20 @@ impl<'tcx> Inliner<'tcx> { checker.visit_basic_block_data(bb, blk); let term = blk.terminator(); + let caller_attrs = tcx.codegen_fn_attrs(self.caller_def_id()); if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind { work_list.push(target); // If the place doesn't actually need dropping, treat it like a regular goto. - let ty = callsite.callee.instantiate_mir( - self.tcx, - ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty), - ); - if ty.needs_drop(tcx, self.typing_env) + let ty = callsite + .callee + .instantiate_mir(tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty)); + if ty.needs_drop(tcx, self.typing_env()) && let UnwindAction::Cleanup(unwind) = unwind { work_list.push(unwind); } - } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set + } else if callee_attrs.instruction_set != caller_attrs.instruction_set && matches!(term.kind, TerminatorKind::InlineAsm { .. }) { // During the attribute checking stage we allow a callee with no @@ -534,7 +389,7 @@ impl<'tcx> Inliner<'tcx> { // assign one. However, during this stage we require an exact match when any // inline-asm is detected. LLVM will still possibly do an inline later on // if the no-attribute function ends up with the same instruction set anyway. - return Err("Cannot move inline-asm across instruction sets"); + return Err("cannot move inline-asm across instruction sets"); } else if let TerminatorKind::TailCall { .. } = term.kind { // FIXME(explicit_tail_calls): figure out how exactly functions containing tail // calls can be inlined (and if they even should) @@ -558,321 +413,710 @@ impl<'tcx> Inliner<'tcx> { } } - fn inline_call( - &self, - caller_body: &mut Body<'tcx>, + fn inline_limit_for_block(&self) -> Option { + match self.history.len() { + 0 => Some(usize::MAX), + 1..=TOP_DOWN_DEPTH_LIMIT => Some(1), + _ => None, + } + } + + fn on_inline_success( + &mut self, callsite: &CallSite<'tcx>, - mut callee_body: Body<'tcx>, + caller_body: &mut Body<'tcx>, + new_blocks: std::ops::Range, ) { - let terminator = caller_body[callsite.block].terminator.take().unwrap(); - let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind - else { - bug!("unexpected terminator kind {:?}", terminator.kind); - }; + self.changed = true; - let return_block = if let Some(block) = target { - // Prepare a new block for code that should execute when call returns. We don't use - // target block directly since it might have other predecessors. - let data = BasicBlockData::new( - Some(Terminator { - source_info: terminator.source_info, - kind: TerminatorKind::Goto { target: block }, - }), - caller_body[block].is_cleanup, - ); - Some(caller_body.basic_blocks_mut().push(data)) - } else { - None + self.history.push(callsite.callee.def_id()); + process_blocks(self, caller_body, new_blocks); + self.history.pop(); + } + + fn on_inline_limit_reached(&self) -> bool { + true + } + + fn on_inline_failure(&self, _: &CallSite<'tcx>, _: &'static str) {} +} + +fn inline<'tcx, T: Inliner<'tcx>>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { + let def_id = body.source.def_id().expect_local(); + + // Only do inlining into fn bodies. + if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() { + return false; + } + + let mut inliner = T::new(tcx, def_id, body); + if !inliner.check_caller_mir_body(body) { + return false; + } + + let blocks = START_BLOCK..body.basic_blocks.next_index(); + process_blocks(&mut inliner, body, blocks); + inliner.changed() +} + +fn process_blocks<'tcx, I: Inliner<'tcx>>( + inliner: &mut I, + caller_body: &mut Body<'tcx>, + blocks: Range, +) { + let Some(inline_limit) = inliner.inline_limit_for_block() else { return }; + let mut inlined_count = 0; + for bb in blocks { + let bb_data = &caller_body[bb]; + if bb_data.is_cleanup { + continue; + } + + let Some(callsite) = resolve_callsite(inliner, caller_body, bb, bb_data) else { + continue; }; - // If the call is something like `a[*i] = f(i)`, where - // `i : &mut usize`, then just duplicating the `a[*i]` - // Place could result in two different locations if `f` - // writes to `i`. To prevent this we need to create a temporary - // borrow of the place and pass the destination as `*temp` instead. - fn dest_needs_borrow(place: Place<'_>) -> bool { - for elem in place.projection.iter() { - match elem { - ProjectionElem::Deref | ProjectionElem::Index(_) => return true, - _ => {} + let span = trace_span!("process_blocks", %callsite.callee, ?bb); + let _guard = span.enter(); + + if !inliner.should_inline_for_callee(callsite.callee.def_id()) { + debug!("not enabled"); + continue; + } + + match try_inlining(inliner, caller_body, &callsite) { + Err(reason) => { + debug!("not-inlined {} [{}]", callsite.callee, reason); + inliner.on_inline_failure(&callsite, reason); + } + Ok(new_blocks) => { + debug!("inlined {}", callsite.callee); + inliner.on_inline_success(&callsite, caller_body, new_blocks); + + inlined_count += 1; + if inlined_count == inline_limit { + if inliner.on_inline_limit_reached() { + return; + } } } + } + } +} + +fn resolve_callsite<'tcx, I: Inliner<'tcx>>( + inliner: &I, + caller_body: &Body<'tcx>, + bb: BasicBlock, + bb_data: &BasicBlockData<'tcx>, +) -> Option> { + let tcx = inliner.tcx(); + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + + // FIXME(explicit_tail_calls): figure out if we can inline tail calls + if let TerminatorKind::Call { ref func, fn_span, .. } = terminator.kind { + let func_ty = func.ty(caller_body, tcx); + if let ty::FnDef(def_id, args) = *func_ty.kind() { + // To resolve an instance its args have to be fully normalized. + let args = tcx.try_normalize_erasing_regions(inliner.typing_env(), args).ok()?; + let callee = + Instance::try_resolve(tcx, inliner.typing_env(), def_id, args).ok().flatten()?; + + if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { + return None; + } - false + if inliner.history().contains(&callee.def_id()) { + return None; + } + + let fn_sig = tcx.fn_sig(def_id).instantiate(tcx, args); + + // Additionally, check that the body that we're inlining actually agrees + // with the ABI of the trait that the item comes from. + if let InstanceKind::Item(instance_def_id) = callee.def + && tcx.def_kind(instance_def_id) == DefKind::AssocFn + && let instance_fn_sig = tcx.fn_sig(instance_def_id).skip_binder() + && instance_fn_sig.abi() != fn_sig.abi() + { + return None; + } + + let source_info = SourceInfo { span: fn_span, ..terminator.source_info }; + + return Some(CallSite { callee, fn_sig, block: bb, source_info }); } + } - let dest = if dest_needs_borrow(destination) { - trace!("creating temp for return destination"); - let dest = Rvalue::Ref( - self.tcx.lifetimes.re_erased, - BorrowKind::Mut { kind: MutBorrowKind::Default }, - destination, - ); - let dest_ty = dest.ty(caller_body, self.tcx); - let temp = - Place::from(self.new_call_temp(caller_body, callsite, dest_ty, return_block)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((temp, dest))), - }); - self.tcx.mk_place_deref(temp) - } else { - destination - }; + None +} - // Always create a local to hold the destination, as `RETURN_PLACE` may appear - // where a full `Place` is not allowed. - let (remap_destination, destination_local) = if let Some(d) = dest.as_local() { - (false, d) - } else { - ( - true, - self.new_call_temp( - caller_body, - callsite, - destination.ty(caller_body, self.tcx).ty, - return_block, - ), - ) - }; +/// Attempts to inline a callsite into the caller body. When successful returns basic blocks +/// containing the inlined body. Otherwise returns an error describing why inlining didn't take +/// place. +fn try_inlining<'tcx, I: Inliner<'tcx>>( + inliner: &I, + caller_body: &mut Body<'tcx>, + callsite: &CallSite<'tcx>, +) -> Result, &'static str> { + let tcx = inliner.tcx(); + check_mir_is_available(inliner, caller_body, callsite.callee)?; + + let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id()); + let cross_crate_inlinable = tcx.cross_crate_inlinable(callsite.callee.def_id()); + check_codegen_attributes(inliner, callsite, callee_attrs, cross_crate_inlinable)?; + + // Intrinsic fallback bodies are automatically made cross-crate inlineable, + // but at this stage we don't know whether codegen knows the intrinsic, + // so just conservatively don't inline it. This also ensures that we do not + // accidentally inline the body of an intrinsic that *must* be overridden. + if tcx.has_attr(callsite.callee.def_id(), sym::rustc_intrinsic) { + return Err("callee is an intrinsic"); + } - // Copy the arguments if needed. - let args = self.make_call_args(args, callsite, caller_body, &callee_body, return_block); + let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); + let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; + let destination_ty = destination.ty(&caller_body.local_decls, tcx).ty; + for arg in args { + if !arg.node.ty(&caller_body.local_decls, tcx).is_sized(tcx, inliner.typing_env()) { + // We do not allow inlining functions with unsized params. Inlining these functions + // could create unsized locals, which are unsound and being phased out. + return Err("call has unsized argument"); + } + } - let mut integrator = Integrator { - args: &args, - new_locals: Local::new(caller_body.local_decls.len()).., - new_scopes: SourceScope::new(caller_body.source_scopes.len()).., - new_blocks: BasicBlock::new(caller_body.basic_blocks.len()).., - destination: destination_local, - callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), - callsite, - cleanup_block: unwind, - in_cleanup_block: false, - return_block, - tcx: self.tcx, - always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), + let callee_body = try_instance_mir(tcx, callsite.callee.def)?; + inliner.check_callee_mir_body(callsite, callee_body, callee_attrs, cross_crate_inlinable)?; + + let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( + tcx, + inliner.typing_env(), + ty::EarlyBinder::bind(callee_body.clone()), + ) else { + debug!("failed to normalize callee body"); + return Err("implementation limitation"); + }; + + // Normally, this shouldn't be required, but trait normalization failure can create a + // validation ICE. + if !validate_types(tcx, inliner.typing_env(), &callee_body, &caller_body).is_empty() { + debug!("failed to validate callee body"); + return Err("implementation limitation"); + } + + // Check call signature compatibility. + // Normally, this shouldn't be required, but trait normalization failure can create a + // validation ICE. + let output_type = callee_body.return_ty(); + if !util::sub_types(tcx, inliner.typing_env(), output_type, destination_ty) { + trace!(?output_type, ?destination_ty); + debug!("failed to normalize return type"); + return Err("implementation limitation"); + } + if callsite.fn_sig.abi() == ExternAbi::RustCall { + // FIXME: Don't inline user-written `extern "rust-call"` functions, + // since this is generally perf-negative on rustc, and we hope that + // LLVM will inline these functions instead. + if callee_body.spread_arg.is_some() { + return Err("user-written rust-call functions"); + } + + let (self_arg, arg_tuple) = match &args[..] { + [arg_tuple] => (None, arg_tuple), + [self_arg, arg_tuple] => (Some(self_arg), arg_tuple), + _ => bug!("Expected `rust-call` to have 1 or 2 args"), }; - // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones - // (or existing ones, in a few special cases) in the caller. - integrator.visit_body(&mut callee_body); + let self_arg_ty = self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, tcx)); - // If there are any locals without storage markers, give them storage only for the - // duration of the call. - for local in callee_body.vars_and_temps_iter() { - if integrator.always_live_locals.contains(local) { - let new_local = integrator.map_local(local); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(new_local), - }); + let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, tcx); + let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else { + bug!("Closure arguments are not passed as a tuple"); + }; + + for (arg_ty, input) in + 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::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) { + trace!(?arg_ty, ?input_type); + debug!("failed to normalize tuple argument type"); + return Err("implementation limitation"); } } - if let Some(block) = return_block { - // To avoid repeated O(n) insert, push any new statements to the end and rotate - // the slice once. - let mut n = 0; - if remap_destination { - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new(( - dest, - Rvalue::Use(Operand::Move(destination_local.into())), - ))), - }); - n += 1; + } else { + 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, tcx); + if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) { + trace!(?arg_ty, ?input_type); + debug!("failed to normalize argument type"); + return Err("implementation limitation"); } - for local in callee_body.vars_and_temps_iter().rev() { - if integrator.always_live_locals.contains(local) { - let new_local = integrator.map_local(local); - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(new_local), - }); - n += 1; - } + } + } + + let old_blocks = caller_body.basic_blocks.next_index(); + inline_call(inliner, caller_body, callsite, callee_body); + let new_blocks = old_blocks..caller_body.basic_blocks.next_index(); + + Ok(new_blocks) +} + +fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( + inliner: &I, + caller_body: &Body<'tcx>, + callee: Instance<'tcx>, +) -> Result<(), &'static str> { + let caller_def_id = caller_body.source.def_id(); + let callee_def_id = callee.def_id(); + if callee_def_id == caller_def_id { + return Err("self-recursion"); + } + + match callee.def { + InstanceKind::Item(_) => { + // If there is no MIR available (either because it was not in metadata or + // because it has no MIR because it's an extern function), then the inliner + // won't cause cycles on this. + if !inliner.tcx().is_mir_available(callee_def_id) { + debug!("item MIR unavailable"); + return Err("implementation limitation"); } - caller_body[block].statements.rotate_right(n); + } + // These have no own callable MIR. + InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { + debug!("instance without MIR (intrinsic / virtual)"); + return Err("implementation limitation"); } - // Insert all of the (mapped) parts of the callee body into the caller. - caller_body.local_decls.extend(callee_body.drain_vars_and_temps()); - caller_body.source_scopes.append(&mut callee_body.source_scopes); - if self - .tcx - .sess - .opts - .unstable_opts - .inline_mir_preserve_debug - .unwrap_or(self.tcx.sess.opts.debuginfo != DebugInfo::None) - { - // Note that we need to preserve these in the standard library so that - // people working on rust can build with or without debuginfo while - // still getting consistent results from the mir-opt tests. - caller_body.var_debug_info.append(&mut callee_body.var_debug_info); + // FIXME(#127030): `ConstParamHasTy` has bad interactions with + // the drop shim builder, which does not evaluate predicates in + // the correct param-env for types being dropped. Stall resolving + // the MIR for this instance until all of its const params are + // substituted. + InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { + debug!("still needs substitution"); + return Err("implementation limitation"); } - caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut()); - caller_body[callsite.block].terminator = Some(Terminator { - source_info: callsite.source_info, - kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) }, - }); + // This cannot result in an immediate cycle since the callee MIR is a shim, which does + // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we + // do not need to catch this here, we can wait until the inliner decides to continue + // inlining a second time. + InstanceKind::VTableShim(_) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => return Ok(()), + } - // Copy required constants from the callee_body into the caller_body. Although we are only - // pushing unevaluated consts to `required_consts`, here they may have been evaluated - // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again. - caller_body.required_consts.as_mut().unwrap().extend( - callee_body.required_consts().into_iter().filter(|ct| ct.const_.is_required_const()), - ); - // Now that we incorporated the callee's `required_consts`, we can remove the callee from - // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does - // some extra work here to save the monomorphization collector work later. It helps a lot, - // since monomorphization can avoid a lot of work when the "mentioned items" are similar to - // the actually used items. By doing this we can entirely avoid visiting the callee! - // We need to reconstruct the `required_item` for the callee so that we can find and - // remove it. - let callee_item = MentionedItem::Fn(func.ty(caller_body, self.tcx)); - let caller_mentioned_items = caller_body.mentioned_items.as_mut().unwrap(); - if let Some(idx) = caller_mentioned_items.iter().position(|item| item.node == callee_item) { - // We found the callee, so remove it and add its items instead. - caller_mentioned_items.remove(idx); - caller_mentioned_items.extend(callee_body.mentioned_items()); - } else { - // If we can't find the callee, there's no point in adding its items. Probably it - // already got removed by being inlined elsewhere in the same function, so we already - // took its items. + if inliner.tcx().is_constructor(callee_def_id) { + trace!("constructors always have MIR"); + // Constructor functions cannot cause a query cycle. + return Ok(()); + } + + if callee_def_id.is_local() { + // If we know for sure that the function we're calling will itself try to + // call us, then we avoid inlining that function. + if inliner.tcx().mir_callgraph_reachable((callee, caller_def_id.expect_local())) { + debug!("query cycle avoidance"); + return Err("caller might be reachable from callee"); } + + Ok(()) + } else { + // This cannot result in an immediate cycle since the callee MIR is from another crate + // and is already optimized. Any subsequent inlining may cause cycles, but we do + // not need to catch this here, we can wait until the inliner decides to continue + // inlining a second time. + trace!("functions from other crates always have MIR"); + Ok(()) } +} - fn make_call_args( - &self, - args: Box<[Spanned>]>, - callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, - callee_body: &Body<'tcx>, - return_block: Option, - ) -> Box<[Local]> { - let tcx = self.tcx; - - // There is a bit of a mismatch between the *caller* of a closure and the *callee*. - // The caller provides the arguments wrapped up in a tuple: - // - // tuple_tmp = (a, b, c) - // Fn::call(closure_ref, tuple_tmp) - // - // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`) - // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has - // the job of unpacking this tuple. But here, we are codegen. =) So we want to create - // a vector like - // - // [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2] - // - // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient - // if we "spill" that into *another* temporary, so that we can map the argument - // variable in the callee MIR directly to an argument variable on our side. - // So we introduce temporaries like: - // - // tmp0 = tuple_tmp.0 - // tmp1 = tuple_tmp.1 - // tmp2 = tuple_tmp.2 - // - // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. - if callsite.fn_sig.abi() == ExternAbi::RustCall && callee_body.spread_arg.is_none() { - // FIXME(edition_2024): switch back to a normal method call. - let mut args = <_>::into_iter(args); - let self_ = self.create_temp_if_necessary( - args.next().unwrap().node, - callsite, - caller_body, - return_block, - ); - let tuple = self.create_temp_if_necessary( - args.next().unwrap().node, - callsite, - caller_body, - return_block, - ); - assert!(args.next().is_none()); - - let tuple = Place::from(tuple); - let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else { - bug!("Closure arguments are not passed as a tuple"); - }; +/// Returns an error if inlining is not possible based on codegen attributes alone. A success +/// indicates that inlining decision should be based on other criteria. +fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>( + inliner: &I, + callsite: &CallSite<'tcx>, + callee_attrs: &CodegenFnAttrs, + cross_crate_inlinable: bool, +) -> Result<(), &'static str> { + let tcx = inliner.tcx(); + if tcx.has_attr(callsite.callee.def_id(), sym::rustc_no_mir_inline) { + return Err("#[rustc_no_mir_inline]"); + } - // The `closure_ref` in our example above. - let closure_ref_arg = iter::once(self_); + if let InlineAttr::Never = callee_attrs.inline { + return Err("never inline attribute"); + } - // The `tmp0`, `tmp1`, and `tmp2` in our example above. - let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| { - // This is e.g., `tuple_tmp.0` in our example above. - let tuple_field = Operand::Move(tcx.mk_place_field(tuple, FieldIdx::new(i), ty)); + // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined + // MIR correctly when Modified Condition/Decision Coverage is enabled. + if tcx.sess.instrument_coverage_mcdc() { + return Err("incompatible with MC/DC coverage"); + } - // Spill to a local to make e.g., `tmp0`. - self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block) - }); + // Reachability pass defines which functions are eligible for inlining. Generally inlining + // other functions is incorrect because they could reference symbols that aren't exported. + let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); + if !is_generic && !cross_crate_inlinable { + return Err("not exported"); + } - closure_ref_arg.chain(tuple_tmp_args).collect() - } else { - // FIXME(edition_2024): switch back to a normal method call. - <_>::into_iter(args) - .map(|a| self.create_temp_if_necessary(a.node, callsite, caller_body, return_block)) - .collect() - } + if callsite.fn_sig.c_variadic() { + return Err("C variadic"); } - /// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh - /// temporary `T` and an instruction `T = arg`, and returns `T`. - fn create_temp_if_necessary( - &self, - arg: Operand<'tcx>, - callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, - return_block: Option, - ) -> Local { - // Reuse the operand if it is a moved temporary. - if let Operand::Move(place) = &arg - && let Some(local) = place.as_local() - && caller_body.local_kind(local) == LocalKind::Temp - { - return local; - } + if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) { + return Err("cold"); + } - // Otherwise, create a temporary for the argument. - trace!("creating temp for argument {:?}", arg); - let arg_ty = arg.ty(caller_body, self.tcx); - let local = self.new_call_temp(caller_body, callsite, arg_ty, return_block); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), - }); - local + let codegen_fn_attrs = tcx.codegen_fn_attrs(inliner.caller_def_id()); + if callee_attrs.no_sanitize != codegen_fn_attrs.no_sanitize { + return Err("incompatible sanitizer set"); } - /// Introduces a new temporary into the caller body that is live for the duration of the call. - fn new_call_temp( - &self, - caller_body: &mut Body<'tcx>, - callsite: &CallSite<'tcx>, - ty: Ty<'tcx>, - return_block: Option, - ) -> Local { - let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span)); + // Two functions are compatible if the callee has no attribute (meaning + // that it's codegen agnostic), or sets an attribute that is identical + // to this function's attribute. + if callee_attrs.instruction_set.is_some() + && callee_attrs.instruction_set != codegen_fn_attrs.instruction_set + { + return Err("incompatible instruction set"); + } + + let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name); + let this_feature_names = codegen_fn_attrs.target_features.iter().map(|f| f.name); + if callee_feature_names.ne(this_feature_names) { + // In general it is not correct to inline a callee with target features that are a + // subset of the caller. This is because the callee might contain calls, and the ABI of + // those calls depends on the target features of the surrounding function. By moving a + // `Call` terminator from one MIR body to another with more target features, we might + // change the ABI of that call! + return Err("incompatible target features"); + } + Ok(()) +} + +fn inline_call<'tcx, I: Inliner<'tcx>>( + inliner: &I, + caller_body: &mut Body<'tcx>, + callsite: &CallSite<'tcx>, + mut callee_body: Body<'tcx>, +) { + let tcx = inliner.tcx(); + let terminator = caller_body[callsite.block].terminator.take().unwrap(); + let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind + else { + bug!("unexpected terminator kind {:?}", terminator.kind); + }; + + let return_block = if let Some(block) = target { + // Prepare a new block for code that should execute when call returns. We don't use + // target block directly since it might have other predecessors. + let data = BasicBlockData::new( + Some(Terminator { + source_info: terminator.source_info, + kind: TerminatorKind::Goto { target: block }, + }), + caller_body[block].is_cleanup, + ); + Some(caller_body.basic_blocks_mut().push(data)) + } else { + None + }; + + // If the call is something like `a[*i] = f(i)`, where + // `i : &mut usize`, then just duplicating the `a[*i]` + // Place could result in two different locations if `f` + // writes to `i`. To prevent this we need to create a temporary + // borrow of the place and pass the destination as `*temp` instead. + fn dest_needs_borrow(place: Place<'_>) -> bool { + for elem in place.projection.iter() { + match elem { + ProjectionElem::Deref | ProjectionElem::Index(_) => return true, + _ => {} + } + } + + false + } + + let dest = if dest_needs_borrow(destination) { + trace!("creating temp for return destination"); + let dest = Rvalue::Ref( + tcx.lifetimes.re_erased, + BorrowKind::Mut { kind: MutBorrowKind::Default }, + destination, + ); + let dest_ty = dest.ty(caller_body, tcx); + let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block)); caller_body[callsite.block].statements.push(Statement { source_info: callsite.source_info, - kind: StatementKind::StorageLive(local), + kind: StatementKind::Assign(Box::new((temp, dest))), }); + tcx.mk_place_deref(temp) + } else { + destination + }; + + // Always create a local to hold the destination, as `RETURN_PLACE` may appear + // where a full `Place` is not allowed. + let (remap_destination, destination_local) = if let Some(d) = dest.as_local() { + (false, d) + } else { + ( + true, + new_call_temp(caller_body, callsite, destination.ty(caller_body, tcx).ty, return_block), + ) + }; - if let Some(block) = return_block { - caller_body[block].statements.insert(0, Statement { + // Copy the arguments if needed. + let args = make_call_args(inliner, args, callsite, caller_body, &callee_body, return_block); + + let mut integrator = Integrator { + args: &args, + new_locals: Local::new(caller_body.local_decls.len()).., + new_scopes: SourceScope::new(caller_body.source_scopes.len()).., + new_blocks: BasicBlock::new(caller_body.basic_blocks.len()).., + destination: destination_local, + callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), + callsite, + cleanup_block: unwind, + in_cleanup_block: false, + return_block, + tcx, + always_live_locals: BitSet::new_filled(callee_body.local_decls.len()), + }; + + // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones + // (or existing ones, in a few special cases) in the caller. + integrator.visit_body(&mut callee_body); + + // If there are any locals without storage markers, give them storage only for the + // duration of the call. + for local in callee_body.vars_and_temps_iter() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[callsite.block].statements.push(Statement { source_info: callsite.source_info, - kind: StatementKind::StorageDead(local), + kind: StatementKind::StorageLive(new_local), }); } + } + if let Some(block) = return_block { + // To avoid repeated O(n) insert, push any new statements to the end and rotate + // the slice once. + let mut n = 0; + if remap_destination { + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::Assign(Box::new(( + dest, + Rvalue::Use(Operand::Move(destination_local.into())), + ))), + }); + n += 1; + } + for local in callee_body.vars_and_temps_iter().rev() { + if integrator.always_live_locals.contains(local) { + let new_local = integrator.map_local(local); + caller_body[block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(new_local), + }); + n += 1; + } + } + caller_body[block].statements.rotate_right(n); + } + + // Insert all of the (mapped) parts of the callee body into the caller. + caller_body.local_decls.extend(callee_body.drain_vars_and_temps()); + caller_body.source_scopes.append(&mut callee_body.source_scopes); + if tcx + .sess + .opts + .unstable_opts + .inline_mir_preserve_debug + .unwrap_or(tcx.sess.opts.debuginfo != DebugInfo::None) + { + // Note that we need to preserve these in the standard library so that + // people working on rust can build with or without debuginfo while + // still getting consistent results from the mir-opt tests. + caller_body.var_debug_info.append(&mut callee_body.var_debug_info); + } + caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut()); + + caller_body[callsite.block].terminator = Some(Terminator { + source_info: callsite.source_info, + kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) }, + }); + + // Copy required constants from the callee_body into the caller_body. Although we are only + // pushing unevaluated consts to `required_consts`, here they may have been evaluated + // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again. + caller_body.required_consts.as_mut().unwrap().extend( + callee_body.required_consts().into_iter().filter(|ct| ct.const_.is_required_const()), + ); + // Now that we incorporated the callee's `required_consts`, we can remove the callee from + // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does + // some extra work here to save the monomorphization collector work later. It helps a lot, + // since monomorphization can avoid a lot of work when the "mentioned items" are similar to + // the actually used items. By doing this we can entirely avoid visiting the callee! + // We need to reconstruct the `required_item` for the callee so that we can find and + // remove it. + let callee_item = MentionedItem::Fn(func.ty(caller_body, tcx)); + let caller_mentioned_items = caller_body.mentioned_items.as_mut().unwrap(); + if let Some(idx) = caller_mentioned_items.iter().position(|item| item.node == callee_item) { + // We found the callee, so remove it and add its items instead. + caller_mentioned_items.remove(idx); + caller_mentioned_items.extend(callee_body.mentioned_items()); + } else { + // If we can't find the callee, there's no point in adding its items. Probably it + // already got removed by being inlined elsewhere in the same function, so we already + // took its items. + } +} + +fn make_call_args<'tcx, I: Inliner<'tcx>>( + inliner: &I, + args: Box<[Spanned>]>, + callsite: &CallSite<'tcx>, + caller_body: &mut Body<'tcx>, + callee_body: &Body<'tcx>, + return_block: Option, +) -> Box<[Local]> { + let tcx = inliner.tcx(); + + // There is a bit of a mismatch between the *caller* of a closure and the *callee*. + // The caller provides the arguments wrapped up in a tuple: + // + // tuple_tmp = (a, b, c) + // Fn::call(closure_ref, tuple_tmp) + // + // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`) + // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has + // the job of unpacking this tuple. But here, we are codegen. =) So we want to create + // a vector like + // + // [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2] + // + // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient + // if we "spill" that into *another* temporary, so that we can map the argument + // variable in the callee MIR directly to an argument variable on our side. + // So we introduce temporaries like: + // + // tmp0 = tuple_tmp.0 + // tmp1 = tuple_tmp.1 + // tmp2 = tuple_tmp.2 + // + // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. + if callsite.fn_sig.abi() == ExternAbi::RustCall && callee_body.spread_arg.is_none() { + // FIXME(edition_2024): switch back to a normal method call. + let mut args = <_>::into_iter(args); + let self_ = create_temp_if_necessary( + inliner, + args.next().unwrap().node, + callsite, + caller_body, + return_block, + ); + let tuple = create_temp_if_necessary( + inliner, + args.next().unwrap().node, + callsite, + caller_body, + return_block, + ); + assert!(args.next().is_none()); + + let tuple = Place::from(tuple); + let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else { + bug!("Closure arguments are not passed as a tuple"); + }; + + // The `closure_ref` in our example above. + let closure_ref_arg = iter::once(self_); + + // The `tmp0`, `tmp1`, and `tmp2` in our example above. + let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| { + // This is e.g., `tuple_tmp.0` in our example above. + let tuple_field = Operand::Move(tcx.mk_place_field(tuple, FieldIdx::new(i), ty)); + + // Spill to a local to make e.g., `tmp0`. + create_temp_if_necessary(inliner, tuple_field, callsite, caller_body, return_block) + }); + + closure_ref_arg.chain(tuple_tmp_args).collect() + } else { + // FIXME(edition_2024): switch back to a normal method call. + <_>::into_iter(args) + .map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block)) + .collect() + } +} - local +/// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh temporary `T` and an +/// instruction `T = arg`, and returns `T`. +fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>( + inliner: &I, + arg: Operand<'tcx>, + callsite: &CallSite<'tcx>, + caller_body: &mut Body<'tcx>, + return_block: Option, +) -> Local { + // Reuse the operand if it is a moved temporary. + if let Operand::Move(place) = &arg + && let Some(local) = place.as_local() + && caller_body.local_kind(local) == LocalKind::Temp + { + return local; + } + + // Otherwise, create a temporary for the argument. + trace!("creating temp for argument {:?}", arg); + let arg_ty = arg.ty(caller_body, inliner.tcx()); + let local = new_call_temp(caller_body, callsite, arg_ty, return_block); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), + }); + local +} + +/// Introduces a new temporary into the caller body that is live for the duration of the call. +fn new_call_temp<'tcx>( + caller_body: &mut Body<'tcx>, + callsite: &CallSite<'tcx>, + ty: Ty<'tcx>, + return_block: Option, +) -> Local { + let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span)); + + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageLive(local), + }); + + if let Some(block) = return_block { + caller_body[block].statements.insert(0, Statement { + source_info: callsite.source_info, + kind: StatementKind::StorageDead(local), + }); } + + local } /** diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index e1fba9be5bb6d..350929ffaa508 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -141,7 +141,7 @@ declare_passes! { mod gvn : GVN; // Made public so that `mir_drops_elaborated_and_const_checked` can be overridden // by custom rustc drivers, running all the steps by themselves. See #114628. - pub mod inline : Inline; + pub mod inline : Inline, ForceInline; mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg }; mod jump_threading : JumpThreading; mod known_panics_lint : KnownPanicsLint; @@ -488,7 +488,9 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & let is_fn_like = tcx.def_kind(def).is_fn_like(); if is_fn_like { // Do not compute the mir call graph without said call graph actually being used. - if pm::should_run_pass(tcx, &inline::Inline) { + if pm::should_run_pass(tcx, &inline::Inline) + || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id()) + { tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); } } @@ -664,6 +666,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Perform instsimplify before inline to eliminate some trivial calls (like clone // shims). &instsimplify::InstSimplify::BeforeInline, + // Perform inlining of `#[rustc_force_inline]`-annotated callees. + &inline::ForceInline, // Perform inlining, which may add a lot of code. &inline::Inline, // Code from other crates may have storage markers, so this needs to happen after diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 8a45ce0762d59..c3f0a989ce105 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -79,6 +79,12 @@ pub(super) trait MirPass<'tcx> { true } + /// Returns `true` if this pass can be overridden by `-Zenable-mir-passes`. This should be + /// true for basically every pass other than those that are necessary for correctness. + fn can_be_overridden(&self) -> bool { + true + } + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); fn is_mir_dump_enabled(&self) -> bool { @@ -176,6 +182,10 @@ where { let name = pass.name(); + if !pass.can_be_overridden() { + return pass.is_enabled(tcx.sess); + } + let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; let overridden = overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index a670da94fcc9e..9444c5b61dd67 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_abi::{ExternAbi, FIRST_VARIANT, Size}; +use rustc_attr_parsing::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::LangItem; use rustc_index::IndexVec; @@ -79,7 +80,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { cfg_checker.fail(location, msg); } - if let MirPhase::Runtime(_) = body.phase { + if let MirPhase::Runtime(phase) = body.phase { if let ty::InstanceKind::Item(_) = body.source.instance { if body.has_free_regions() { cfg_checker.fail( @@ -88,6 +89,27 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { ); } } + + if phase >= RuntimePhase::Optimized + && body + .basic_blocks + .iter() + .filter_map(|bb| match &bb.terminator().kind { + TerminatorKind::Call { func, .. } + | TerminatorKind::TailCall { func, .. } => Some(func), + _ => None, + }) + .filter_map(|func| match func.ty(&body.local_decls, tcx).kind() { + ty::FnDef(did, ..) => Some(did), + _ => None, + }) + .any(|did| matches!(tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. })) + { + cfg_checker.fail( + Location::START, + "`#[rustc_force_inline]`-annotated function not inlined", + ); + } } } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 00aae03704fb6..f3232a0e15d9a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -207,6 +207,7 @@ use std::path::PathBuf; +use rustc_attr_parsing::InlineAttr; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; @@ -959,6 +960,14 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - return false; } + if tcx.def_kind(def_id).has_codegen_attrs() + && matches!(tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. }) + { + // `#[rustc_force_inline]` items should never be codegened. This should be caught by + // the MIR validator. + return false; + } + if def_id.is_local() { // Local items cannot be referred to locally without monomorphizing them locally. return true; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f39bea2a56fcc..9df396cbf7a8c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -656,6 +656,14 @@ passes_rustc_allow_const_fn_unstable = passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled +passes_rustc_force_inline = + attribute should be applied to a function + .label = not a function definition + +passes_rustc_force_inline_coro = + attribute cannot be applied to a `async`, `gen` or `async gen` function + .label = `async`, `gen` or `async gen` function + passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7656ca86c1848..1b2b8ac5dd9e7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -247,7 +247,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_coroutine(attr, target); } [sym::linkage, ..] => self.check_linkage(attr, span, target), - [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent( attr.span, span, attrs), + [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs), [ // ok sym::allow @@ -332,6 +332,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_repr(attrs, span, target, item, hir_id); self.check_used(attrs, target, span); + self.check_rustc_force_inline(hir_id, attrs, span, target); } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { @@ -2480,6 +2481,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_rustc_force_inline( + &self, + hir_id: HirId, + attrs: &[Attribute], + span: Span, + target: Target, + ) { + let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline)); + match (target, force_inline_attr) { + (Target::Closure, None) => { + let is_coro = matches!( + self.tcx.hir().expect_expr(hir_id).kind, + hir::ExprKind::Closure(hir::Closure { + kind: hir::ClosureKind::Coroutine(..) + | hir::ClosureKind::CoroutineClosure(..), + .. + }) + ); + let parent_did = self.tcx.hir().get_parent_item(hir_id).to_def_id(); + let parent_span = self.tcx.def_span(parent_did); + let parent_force_inline_attr = + self.tcx.get_attr(parent_did, sym::rustc_force_inline); + if let Some(attr) = parent_force_inline_attr + && is_coro + { + self.dcx().emit_err(errors::RustcForceInlineCoro { + attr_span: attr.span, + span: parent_span, + }); + } + } + (Target::Fn, _) => (), + (_, Some(attr)) => { + self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span }); + } + (_, None) => (), + } + } + /// Checks if `#[autodiff]` is applied to an item other than a function item. fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) { debug!("check_autodiff"); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index d95fa5db0ceee..13da021c6143a 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -688,6 +688,24 @@ pub(crate) struct RustcPubTransparent { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_rustc_force_inline)] +pub(crate) struct RustcForceInline { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_rustc_force_inline_coro)] +pub(crate) struct RustcForceInlineCoro { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_link_ordinal)] pub(crate) struct LinkOrdinal { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ef1e2c20978c4..a5bf5e06485a9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1731,6 +1731,7 @@ symbols! { rustc_error, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, + rustc_force_inline, rustc_has_incoherent_inherent_impls, rustc_hidden_type_of_opaques, rustc_if_this_changed, diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 1ab89ecde7a44..b82bb27eb795a 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -251,7 +251,9 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a trait_selection_nothing = {""} -trait_selection_oc_cant_coerce = cannot coerce intrinsics to function pointers +trait_selection_oc_cant_coerce_force_inline = + cannot coerce functions which must be inlined to function pointers +trait_selection_oc_cant_coerce_intrinsic = cannot coerce intrinsics to function pointers trait_selection_oc_closure_selfref = closure/coroutine type that references itself trait_selection_oc_const_compat = const not compatible with trait trait_selection_oc_fn_lang_correct_type = {$lang_item_name -> diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index d279590d45ae9..53300c95fa709 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2294,7 +2294,7 @@ impl<'tcx> ObligationCause<'tcx> { { FailureCode::Error0644 } - TypeError::IntrinsicCast => FailureCode::Error0308, + TypeError::IntrinsicCast | TypeError::ForceInlineCast => FailureCode::Error0308, _ => FailureCode::Error0308, }, } @@ -2360,8 +2360,11 @@ impl<'tcx> ObligationCause<'tcx> { { ObligationCauseFailureCode::ClosureSelfref { span } } + TypeError::ForceInlineCast => { + ObligationCauseFailureCode::CantCoerceForceInline { span, subdiags } + } TypeError::IntrinsicCast => { - ObligationCauseFailureCode::CantCoerce { span, subdiags } + ObligationCauseFailureCode::CantCoerceIntrinsic { span, subdiags } } _ => ObligationCauseFailureCode::Generic { span, subdiags }, }, diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index a8fddff4e4a87..53a4e5031c6dd 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1729,8 +1729,15 @@ pub enum ObligationCauseFailureCode { #[primary_span] span: Span, }, - #[diag(trait_selection_oc_cant_coerce, code = E0308)] - CantCoerce { + #[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)] + CantCoerceForceInline { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)] + CantCoerceIntrinsic { #[primary_span] span: Span, #[subdiagnostic] diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 55671b84dbc4f..68b11489ae7c1 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -51,6 +51,9 @@ pub enum TypeError { ConstMismatch(ExpectedFound), IntrinsicCast, + /// `#[rustc_force_inline]` functions must be inlined and must not be codegened independently, + /// so casting to a function pointer must be prohibited. + ForceInlineCast, /// Safe `#[target_feature]` functions are not assignable to safe function pointers. TargetFeatureCast(I::DefId), } @@ -83,6 +86,7 @@ impl TypeError { | ProjectionMismatched(_) | ExistentialMismatch(_) | ConstMismatch(_) + | ForceInlineCast | IntrinsicCast => true, } } diff --git a/tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff new file mode 100644 index 0000000000000..f894f06e5a0ab --- /dev/null +++ b/tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined callee_forced) { ++ } + + bb0: { + StorageLive(_1); +- _1 = callee_forced() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff new file mode 100644 index 0000000000000..7b70fd665666a --- /dev/null +++ b/tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined callee_forced) { ++ } + + bb0: { + StorageLive(_1); +- _1 = callee_forced() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced.rs b/tests/mir-opt/inline/forced.rs new file mode 100644 index 0000000000000..0447ef2e4d787 --- /dev/null +++ b/tests/mir-opt/inline/forced.rs @@ -0,0 +1,13 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +#![feature(rustc_attrs)] + +#[rustc_force_inline] +pub fn callee_forced() {} + +// EMIT_MIR forced.caller.ForceInline.diff +pub fn caller() { + callee_forced(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined callee_forced) +} diff --git a/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff new file mode 100644 index 0000000000000..42048bceef84e --- /dev/null +++ b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff @@ -0,0 +1,12 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> {async fn body of caller()} { + let mut _0: {async fn body of caller()}; + + bb0: { + _0 = {coroutine@$DIR/forced_async.rs:10:19: 14:2 (#0)}; + return; + } + } + diff --git a/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff new file mode 100644 index 0000000000000..42048bceef84e --- /dev/null +++ b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,12 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> {async fn body of caller()} { + let mut _0: {async fn body of caller()}; + + bb0: { + _0 = {coroutine@$DIR/forced_async.rs:10:19: 14:2 (#0)}; + return; + } + } + diff --git a/tests/mir-opt/inline/forced_async.rs b/tests/mir-opt/inline/forced_async.rs new file mode 100644 index 0000000000000..456f8fdc5cee0 --- /dev/null +++ b/tests/mir-opt/inline/forced_async.rs @@ -0,0 +1,14 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +//@ edition: 2021 +#![feature(rustc_attrs)] + +#[rustc_force_inline] +pub fn callee_forced() {} + +// EMIT_MIR forced_async.caller.ForceInline.diff +async fn caller() { + callee_forced(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined callee_forced) +} diff --git a/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff new file mode 100644 index 0000000000000..def2375efd068 --- /dev/null +++ b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller::{closure#0}` before ForceInline ++ // MIR for `caller::{closure#0}` after ForceInline + + fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure.rs:10:6: 10:8}) -> () { + let mut _0: (); + let _2: (); ++ scope 1 (inlined callee_forced) { ++ } + + bb0: { + StorageLive(_2); +- _2 = callee_forced() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_2); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff new file mode 100644 index 0000000000000..8f50c20587d70 --- /dev/null +++ b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller::{closure#0}` before ForceInline ++ // MIR for `caller::{closure#0}` after ForceInline + + fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure.rs:10:6: 10:8}) -> () { + let mut _0: (); + let _2: (); ++ scope 1 (inlined callee_forced) { ++ } + + bb0: { + StorageLive(_2); +- _2 = callee_forced() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_2); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_closure.rs b/tests/mir-opt/inline/forced_closure.rs new file mode 100644 index 0000000000000..a5590d6c7f001 --- /dev/null +++ b/tests/mir-opt/inline/forced_closure.rs @@ -0,0 +1,15 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +#![feature(rustc_attrs)] + +#[rustc_force_inline] +pub fn callee_forced() {} + +// EMIT_MIR forced_closure.caller-{closure#0}.ForceInline.diff +pub fn caller() { + (|| { + callee_forced(); + // CHECK-LABEL: fn caller::{closure#0}( + // CHECK: (inlined callee_forced) + })(); +} diff --git a/tests/ui/force-inlining/auxiliary/callees.rs b/tests/ui/force-inlining/auxiliary/callees.rs new file mode 100644 index 0000000000000..7468b8f10985d --- /dev/null +++ b/tests/ui/force-inlining/auxiliary/callees.rs @@ -0,0 +1,10 @@ +//@ compile-flags: --crate-type=lib +#![feature(rustc_attrs)] + +#[rustc_force_inline = "the test requires it"] +pub fn forced_with_reason() { +} + +#[rustc_force_inline] +pub fn forced() { +} diff --git a/tests/ui/force-inlining/cast.rs b/tests/ui/force-inlining/cast.rs new file mode 100644 index 0000000000000..8f51ec8397736 --- /dev/null +++ b/tests/ui/force-inlining/cast.rs @@ -0,0 +1,25 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(rustc_attrs)] + +#[rustc_force_inline] +pub fn callee(x: isize) -> usize { unimplemented!() } + +fn a() { + let _: fn(isize) -> usize = callee; +//~^ ERROR cannot coerce functions which must be inlined to function pointers +} + +fn b() { + let _ = callee as fn(isize) -> usize; +//~^ ERROR non-primitive cast +} + +fn c() { + let _: [fn(isize) -> usize; 2] = [ + callee, +//~^ ERROR cannot coerce functions which must be inlined to function pointers + callee, + ]; +} diff --git a/tests/ui/force-inlining/cast.stderr b/tests/ui/force-inlining/cast.stderr new file mode 100644 index 0000000000000..116919e5fe7f0 --- /dev/null +++ b/tests/ui/force-inlining/cast.stderr @@ -0,0 +1,40 @@ +error[E0308]: cannot coerce functions which must be inlined to function pointers + --> $DIR/cast.rs:10:33 + | +LL | let _: fn(isize) -> usize = callee; + | ------------------ ^^^^^^ cannot coerce functions which must be inlined to function pointers + | | + | expected due to this + | + = note: expected fn pointer `fn(_) -> _` + found fn item `fn(_) -> _ {callee}` + = note: fn items are distinct from fn pointers +help: consider casting to a fn pointer + | +LL | let _: fn(isize) -> usize = callee as fn(isize) -> usize; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0605]: non-primitive cast: `fn(isize) -> usize {callee}` as `fn(isize) -> usize` + --> $DIR/cast.rs:15:13 + | +LL | let _ = callee as fn(isize) -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast + +error[E0308]: cannot coerce functions which must be inlined to function pointers + --> $DIR/cast.rs:21:9 + | +LL | callee, + | ^^^^^^ cannot coerce functions which must be inlined to function pointers + | + = note: expected fn pointer `fn(_) -> _` + found fn item `fn(_) -> _ {callee}` + = note: fn items are distinct from fn pointers +help: consider casting to a fn pointer + | +LL | callee as fn(isize) -> usize, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0605. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/force-inlining/cross-crate.rs b/tests/ui/force-inlining/cross-crate.rs new file mode 100644 index 0000000000000..a3f0c2c873ea8 --- /dev/null +++ b/tests/ui/force-inlining/cross-crate.rs @@ -0,0 +1,13 @@ +//@ aux-build:callees.rs +//@ build-pass +//@ compile-flags: --crate-type=lib + +extern crate callees; + +// Test that forced inlining across crates works as expected. + +pub fn caller() { + callees::forced(); + + callees::forced_with_reason(); +} diff --git a/tests/ui/force-inlining/deny-async.rs b/tests/ui/force-inlining/deny-async.rs new file mode 100644 index 0000000000000..d5b6dc000f70d --- /dev/null +++ b/tests/ui/force-inlining/deny-async.rs @@ -0,0 +1,25 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib +//@ edition: 2021 +#![allow(internal_features)] +#![feature(rustc_attrs)] + +// Test that forced inlining into async functions w/ errors works as expected. + +#[rustc_no_mir_inline] +#[rustc_force_inline] +pub fn callee() { +} + +#[rustc_no_mir_inline] +#[rustc_force_inline = "the test requires it"] +pub fn callee_justified() { +} + +async fn async_caller() { + callee(); +//~^ ERROR `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined + + callee_justified(); +//~^ ERROR `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined +} diff --git a/tests/ui/force-inlining/deny-async.stderr b/tests/ui/force-inlining/deny-async.stderr new file mode 100644 index 0000000000000..7b077174ee89e --- /dev/null +++ b/tests/ui/force-inlining/deny-async.stderr @@ -0,0 +1,19 @@ +error: `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined + --> $DIR/deny-async.rs:20:5 + | +LL | callee(); + | ^^^^^^^^ ...`callee` called here + | + = note: could not be inlined due to: #[rustc_no_mir_inline] + +error: `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined + --> $DIR/deny-async.rs:23:5 + | +LL | callee_justified(); + | ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here + | + = note: could not be inlined due to: #[rustc_no_mir_inline] + = note: `callee_justified` is required to be inlined to: the test requires it + +error: aborting due to 2 previous errors + diff --git a/tests/ui/force-inlining/deny-closure.rs b/tests/ui/force-inlining/deny-closure.rs new file mode 100644 index 0000000000000..0057f1e78540c --- /dev/null +++ b/tests/ui/force-inlining/deny-closure.rs @@ -0,0 +1,26 @@ +//@ build-fail +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(rustc_attrs)] + +// Test that forced inlining into closures w/ errors works as expected. + +#[rustc_no_mir_inline] +#[rustc_force_inline] +pub fn callee() { +} + +#[rustc_no_mir_inline] +#[rustc_force_inline = "the test requires it"] +pub fn callee_justified() { +} + +pub fn caller() { + (|| { + callee(); +//~^ ERROR `callee` could not be inlined into `caller::{closure#0}` but is required to be inlined + + callee_justified(); +//~^ ERROR `callee_justified` could not be inlined into `caller::{closure#0}` but is required to be inlined + })(); +} diff --git a/tests/ui/force-inlining/deny-closure.stderr b/tests/ui/force-inlining/deny-closure.stderr new file mode 100644 index 0000000000000..7d42145f1c878 --- /dev/null +++ b/tests/ui/force-inlining/deny-closure.stderr @@ -0,0 +1,28 @@ +error: `callee` could not be inlined into `caller::{closure#0}` but is required to be inlined + --> $DIR/deny-closure.rs:20:9 + | +LL | callee(); + | ^^^^^^^^ ...`callee` called here + | + = note: could not be inlined due to: #[rustc_no_mir_inline] + +error: `callee_justified` could not be inlined into `caller::{closure#0}` but is required to be inlined + --> $DIR/deny-closure.rs:23:9 + | +LL | callee_justified(); + | ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here + | + = note: could not be inlined due to: #[rustc_no_mir_inline] + = note: `callee_justified` is required to be inlined to: the test requires it + +note: the above error was encountered while instantiating `fn caller::{closure#0}` + --> $DIR/deny-closure.rs:19:5 + | +LL | / (|| { +LL | | callee(); +... | +LL | | })(); + | |________^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/force-inlining/deny.rs b/tests/ui/force-inlining/deny.rs new file mode 100644 index 0000000000000..a19e820cff28d --- /dev/null +++ b/tests/ui/force-inlining/deny.rs @@ -0,0 +1,24 @@ +//@ build-fail +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(rustc_attrs)] + +// Test that forced inlining w/ errors works as expected. + +#[rustc_no_mir_inline] +#[rustc_force_inline] +pub fn callee() { +} + +#[rustc_no_mir_inline] +#[rustc_force_inline = "the test requires it"] +pub fn callee_justified() { +} + +pub fn caller() { + callee(); +//~^ ERROR `callee` could not be inlined into `caller` but is required to be inlined + + callee_justified(); +//~^ ERROR `callee_justified` could not be inlined into `caller` but is required to be inlined +} diff --git a/tests/ui/force-inlining/deny.stderr b/tests/ui/force-inlining/deny.stderr new file mode 100644 index 0000000000000..3983bead182eb --- /dev/null +++ b/tests/ui/force-inlining/deny.stderr @@ -0,0 +1,19 @@ +error: `callee` could not be inlined into `caller` but is required to be inlined + --> $DIR/deny.rs:19:5 + | +LL | callee(); + | ^^^^^^^^ ...`callee` called here + | + = note: could not be inlined due to: #[rustc_no_mir_inline] + +error: `callee_justified` could not be inlined into `caller` but is required to be inlined + --> $DIR/deny.rs:22:5 + | +LL | callee_justified(); + | ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here + | + = note: could not be inlined due to: #[rustc_no_mir_inline] + = note: `callee_justified` is required to be inlined to: the test requires it + +error: aborting due to 2 previous errors + diff --git a/tests/ui/force-inlining/gate.rs b/tests/ui/force-inlining/gate.rs new file mode 100644 index 0000000000000..d6a01a74a44b5 --- /dev/null +++ b/tests/ui/force-inlining/gate.rs @@ -0,0 +1,12 @@ +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] + +#[rustc_force_inline] +//~^ ERROR #![rustc_force_inline] forces a free function to be inlined +pub fn bare() { +} + +#[rustc_force_inline = "the test requires it"] +//~^ ERROR #![rustc_force_inline] forces a free function to be inlined +pub fn justified() { +} diff --git a/tests/ui/force-inlining/gate.stderr b/tests/ui/force-inlining/gate.stderr new file mode 100644 index 0000000000000..e3973a08c232b --- /dev/null +++ b/tests/ui/force-inlining/gate.stderr @@ -0,0 +1,21 @@ +error[E0658]: #![rustc_force_inline] forces a free function to be inlined + --> $DIR/gate.rs:4:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: #![rustc_force_inline] forces a free function to be inlined + --> $DIR/gate.rs:9:1 + | +LL | #[rustc_force_inline = "the test requires it"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs new file mode 100644 index 0000000000000..7574078b245c2 --- /dev/null +++ b/tests/ui/force-inlining/invalid.rs @@ -0,0 +1,164 @@ +//@ edition: 2024 +#![allow(internal_features, unused_imports, unused_macros)] +#![feature(extern_types)] +#![feature(gen_blocks)] +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![feature(trait_alias)] + +// Test that invalid force inlining attributes error as expected. + +#[rustc_force_inline("foo")] +//~^ ERROR malformed `rustc_force_inline` attribute input +pub fn forced1() { +} + +#[rustc_force_inline(bar, baz)] +//~^ ERROR malformed `rustc_force_inline` attribute input +pub fn forced2() { +} + +#[rustc_force_inline(2)] +//~^ ERROR malformed `rustc_force_inline` attribute input +pub fn forced3() { +} + +#[rustc_force_inline = 2] +//~^ ERROR malformed `rustc_force_inline` attribute input +pub fn forced4() { +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +extern crate std as other_std; + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +use std::collections::HashMap; + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +static _FOO: &'static str = "FOO"; + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +const _BAR: u32 = 3; + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +mod foo { } + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +unsafe extern "C" { + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + static X: &'static u32; + + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + type Y; + + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + fn foo(); +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +type Foo = u32; + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +enum Bar<#[rustc_force_inline] T> { +//~^ ERROR attribute should be applied to a function + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + Baz(std::marker::PhantomData), +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +struct Qux { + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + field: u32, +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +union FooBar { + x: u32, + y: u32, +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +trait FooBaz { + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + type Foo; + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + const Bar: i32; + + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + fn foo() {} +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +trait FooQux = FooBaz; + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +impl Bar { + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + fn foo() {} +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +impl FooBaz for Bar { + type Foo = u32; + const Bar: i32 = 3; +} + +#[rustc_force_inline] +//~^ ERROR attribute should be applied to a function +macro_rules! barqux { ($foo:tt) => { $foo }; } + +fn barqux(#[rustc_force_inline] _x: u32) {} +//~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters +//~^^ ERROR attribute should be applied to a function + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +async fn async_foo() {} + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +gen fn gen_foo() {} + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +async gen fn async_gen_foo() {} + +fn main() { + let _x = #[rustc_force_inline] || { }; +//~^ ERROR attribute should be applied to a function + let _y = #[rustc_force_inline] 3 + 4; +//~^ ERROR attribute should be applied to a function + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + let _z = 3; + + match _z { + #[rustc_force_inline] +//~^ ERROR attribute should be applied to a function + 1 => (), + _ => (), + } +} diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr new file mode 100644 index 0000000000000..5d280124129be --- /dev/null +++ b/tests/ui/force-inlining/invalid.stderr @@ -0,0 +1,377 @@ +error: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:11:1 + | +LL | #[rustc_force_inline("foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[rustc_force_inline = "reason"] + | +LL | #[rustc_force_inline] + | + +error: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:16:1 + | +LL | #[rustc_force_inline(bar, baz)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[rustc_force_inline = "reason"] + | +LL | #[rustc_force_inline] + | + +error: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:21:1 + | +LL | #[rustc_force_inline(2)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[rustc_force_inline = "reason"] + | +LL | #[rustc_force_inline] + | + +error: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:26:1 + | +LL | #[rustc_force_inline = 2] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[rustc_force_inline = "reason"] + | +LL | #[rustc_force_inline] + | + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/invalid.rs:133:11 + | +LL | fn barqux(#[rustc_force_inline] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: attribute should be applied to a function + --> $DIR/invalid.rs:31:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | extern crate std as other_std; + | ------------------------------ not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:35:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | use std::collections::HashMap; + | ------------------------------ not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:39:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | static _FOO: &'static str = "FOO"; + | ---------------------------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:43:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | const _BAR: u32 = 3; + | -------------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:47:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | mod foo { } + | ----------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:51:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / unsafe extern "C" { +LL | | #[rustc_force_inline] +LL | | +LL | | static X: &'static u32; +... | +LL | | fn foo(); +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:67:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Foo = u32; + | --------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:71:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / enum Bar<#[rustc_force_inline] T> { +LL | | +LL | | #[rustc_force_inline] +... | +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:73:10 + | +LL | enum Bar<#[rustc_force_inline] T> { + | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:75:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | Baz(std::marker::PhantomData), + | -------------------------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:80:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / struct Qux { +LL | | #[rustc_force_inline] +LL | | +LL | | field: u32, +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:83:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | field: u32, + | ---------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:88:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / union FooBar { +LL | | x: u32, +LL | | y: u32, +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:95:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / trait FooBaz { +LL | | #[rustc_force_inline] +LL | | +LL | | type Foo; +... | +LL | | fn foo() {} +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:110:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | trait FooQux = FooBaz; + | ---------------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:114:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / impl Bar { +LL | | #[rustc_force_inline] +LL | | +LL | | fn foo() {} +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:122:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / impl FooBaz for Bar { +LL | | type Foo = u32; +LL | | const Bar: i32 = 3; +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:129:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | macro_rules! barqux { ($foo:tt) => { $foo }; } + | ---------------------------------------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:133:11 + | +LL | fn barqux(#[rustc_force_inline] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^-------- + | | + | not a function definition + +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid.rs:137:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | async fn async_foo() {} + | -------------------- `async`, `gen` or `async gen` function + +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid.rs:141:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | gen fn gen_foo() {} + | ---------------- `async`, `gen` or `async gen` function + +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid.rs:145:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | async gen fn async_gen_foo() {} + | ---------------------------- `async`, `gen` or `async gen` function + +error: attribute should be applied to a function + --> $DIR/invalid.rs:150:14 + | +LL | let _x = #[rustc_force_inline] || { }; + | ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:152:14 + | +LL | let _y = #[rustc_force_inline] 3 + 4; + | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:154:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | let _z = 3; + | ----------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:159:9 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | 1 => (), + | ------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:98:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Foo; + | --------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:101:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | const Bar: i32; + | --------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:105:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo() {} + | ----------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:117:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo() {} + | ----------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:54:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | static X: &'static u32; + | ----------------------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:58:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Y; + | ------- not a function definition + +error: attribute should be applied to a function + --> $DIR/invalid.rs:62:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo(); + | --------- not a function definition + +error: aborting due to 38 previous errors + From 02d423cd24944b17783e9fa4062e6a4e8e4d351f Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 10 Dec 2024 12:05:24 +0000 Subject: [PATCH 180/189] codegen_attrs: force inlining takes precedence --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d8f62d543ad84..a78826a462945 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -523,41 +523,46 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.has_name(sym::inline) { - if attr.is_word() { - InlineAttr::Hint - } else if let Some(ref items) = attr.meta_item_list() { - inline_span = Some(attr.span); - if items.len() != 1 { - struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); - InlineAttr::None - } else if list_contains_name(items, sym::always) { - InlineAttr::Always - } else if list_contains_name(items, sym::never) { - InlineAttr::Never - } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); + if !attr.has_name(sym::inline) { + return ia; + } - InlineAttr::None - } - } else { - ia - } - } else if attr.has_name(sym::rustc_force_inline) && tcx.features().rustc_attrs() { - if attr.is_word() { - InlineAttr::Force { attr_span: attr.span, reason: None } - } else if let Some(val) = attr.value_str() { - InlineAttr::Force { attr_span: attr.span, reason: Some(val) } + if attr.is_word() { + InlineAttr::Hint + } else if let Some(ref items) = attr.meta_item_list() { + inline_span = Some(attr.span); + if items.len() != 1 { + struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); + InlineAttr::None + } else if list_contains_name(items, sym::always) { + InlineAttr::Always + } else if list_contains_name(items, sym::never) { + InlineAttr::Never } else { - debug!("`rustc_force_inline` not checked by attribute validation"); - ia + struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") + .with_help("valid inline arguments are `always` and `never`") + .emit(); + + InlineAttr::None } } else { ia } }); + codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| { + if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() { + return ia; + } + + if attr.is_word() { + InlineAttr::Force { attr_span: attr.span, reason: None } + } else if let Some(val) = attr.value_str() { + InlineAttr::Force { attr_span: attr.span, reason: Some(val) } + } else { + debug!("`rustc_force_inline` not checked by attribute validation"); + ia + } + }); // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be From 450793923ef1941bfca291f4deebf3c902d59c2f Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 10 Dec 2024 12:06:24 +0000 Subject: [PATCH 181/189] inline: force inlining shims --- compiler/rustc_mir_transform/src/inline.rs | 26 +++++++++++++--------- compiler/rustc_mir_transform/src/shim.rs | 4 +++- tests/ui/force-inlining/shims.rs | 9 ++++++++ 3 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 tests/ui/force-inlining/shims.rs diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index a5a4b5987f567..cdb0ed761cf98 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -6,7 +6,7 @@ use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; use rustc_attr_parsing::InlineAttr; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_index::Idx; use rustc_index::bit_set::BitSet; use rustc_middle::bug; @@ -98,12 +98,12 @@ impl<'tcx> crate::MirPass<'tcx> for ForceInline { } trait Inliner<'tcx> { - fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) -> Self; + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self; fn tcx(&self) -> TyCtxt<'tcx>; fn typing_env(&self) -> ty::TypingEnv<'tcx>; fn history(&self) -> &[DefId]; - fn caller_def_id(&self) -> LocalDefId; + fn caller_def_id(&self) -> DefId; /// Has the caller body been changed? fn changed(self) -> bool; @@ -146,7 +146,7 @@ struct ForceInliner<'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, /// `DefId` of caller. - def_id: LocalDefId, + def_id: DefId, /// Stack of inlined instances. /// We only check the `DefId` and not the args because we want to /// avoid inlining cases of polymorphic recursion. @@ -158,7 +158,7 @@ struct ForceInliner<'tcx> { } impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { - fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) -> Self { + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self { Self { tcx, typing_env: body.typing_env(tcx), def_id, history: Vec::new(), changed: false } } @@ -174,7 +174,7 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { &self.history } - fn caller_def_id(&self) -> LocalDefId { + fn caller_def_id(&self) -> DefId { self.def_id } @@ -248,7 +248,7 @@ struct NormalInliner<'tcx> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, /// `DefId` of caller. - def_id: LocalDefId, + def_id: DefId, /// Stack of inlined instances. /// We only check the `DefId` and not the args because we want to /// avoid inlining cases of polymorphic recursion. @@ -263,7 +263,7 @@ struct NormalInliner<'tcx> { } impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { - fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) -> Self { + fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self { let typing_env = body.typing_env(tcx); let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); @@ -284,7 +284,7 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { self.tcx } - fn caller_def_id(&self) -> LocalDefId { + fn caller_def_id(&self) -> DefId { self.def_id } @@ -442,7 +442,7 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { } fn inline<'tcx, T: Inliner<'tcx>>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { - let def_id = body.source.def_id().expect_local(); + let def_id = body.source.def_id(); // Only do inlining into fn bodies. if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() { @@ -723,7 +723,11 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( return Ok(()); } - if callee_def_id.is_local() { + if callee_def_id.is_local() + && !inliner + .tcx() + .is_lang_item(inliner.tcx().parent(caller_def_id), rustc_hir::LangItem::FnOnce) + { // If we know for sure that the function we're calling will itself try to // call us, then we avoid inlining that function. if inliner.tcx().mir_callgraph_reachable((callee, caller_def_id.expect_local())) { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 722da3c420dc9..4648ec33c9345 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -20,7 +20,7 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use crate::{ - abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, + abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, inline, instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify, }; @@ -155,6 +155,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::MakeShim, &instsimplify::InstSimplify::BeforeInline, + // Perform inlining of `#[rustc_force_inline]`-annotated callees. + &inline::ForceInline, &abort_unwinding_calls::AbortUnwindingCalls, &add_call_guards::CriticalCallEdges, ], diff --git a/tests/ui/force-inlining/shims.rs b/tests/ui/force-inlining/shims.rs new file mode 100644 index 0000000000000..03b7d07cda39e --- /dev/null +++ b/tests/ui/force-inlining/shims.rs @@ -0,0 +1,9 @@ +//@ build-pass +#![allow(internal_features)] +#![feature(rustc_attrs)] + +#[rustc_force_inline] +fn f() {} +fn g(t: T) { t(); } + +fn main() { g(f); } From e4bae91be11c81b8c68a7bb521dfa17ccef3fc24 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 10 Dec 2024 12:06:57 +0000 Subject: [PATCH 182/189] inline: re-introduce some callee body checks --- compiler/rustc_mir_transform/src/inline.rs | 31 +++++++++- tests/ui/force-inlining/asm.rs | 68 ++++++++++++++++++++++ tests/ui/force-inlining/asm.stderr | 34 +++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 tests/ui/force-inlining/asm.rs create mode 100644 tests/ui/force-inlining/asm.stderr diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index cdb0ed761cf98..a98901a668822 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -195,10 +195,37 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { &self, _: &CallSite<'tcx>, callee_body: &Body<'tcx>, - _: &CodegenFnAttrs, + callee_attrs: &CodegenFnAttrs, _: bool, ) -> Result<(), &'static str> { - if let Some(_) = callee_body.tainted_by_errors { Err("body has errors") } else { Ok(()) } + if callee_body.tainted_by_errors.is_some() { + return Err("body has errors"); + } + + let caller_attrs = self.tcx().codegen_fn_attrs(self.caller_def_id()); + if callee_attrs.instruction_set != caller_attrs.instruction_set + && callee_body + .basic_blocks + .iter() + .any(|bb| matches!(bb.terminator().kind, TerminatorKind::InlineAsm { .. })) + { + // During the attribute checking stage we allow a callee with no + // instruction_set assigned to count as compatible with a function that does + // assign one. However, during this stage we require an exact match when any + // inline-asm is detected. LLVM will still possibly do an inline later on + // if the no-attribute function ends up with the same instruction set anyway. + Err("cannot move inline-asm across instruction sets") + } else if callee_body + .basic_blocks + .iter() + .any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. })) + { + // FIXME(explicit_tail_calls): figure out how exactly functions containing tail + // calls can be inlined (and if they even should) + Err("can't inline functions with tail calls") + } else { + Ok(()) + } } fn inline_limit_for_block(&self) -> Option { diff --git a/tests/ui/force-inlining/asm.rs b/tests/ui/force-inlining/asm.rs new file mode 100644 index 0000000000000..85014ffa51588 --- /dev/null +++ b/tests/ui/force-inlining/asm.rs @@ -0,0 +1,68 @@ +//@ build-fail +//@ compile-flags: --crate-type=lib --target thumbv4t-none-eabi +//@ needs-llvm-components: arm + +// Checks that forced inlining won't mix asm with incompatible instruction sets. + +#![crate_type = "lib"] +#![feature(rustc_attrs)] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +#[lang = "freeze"] +pub unsafe trait Freeze {} + +#[lang = "start"] +fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + 0 +} + +#[rustc_builtin_macro] +#[macro_export] +macro_rules! asm { + ("assembly template", + $(operands,)* + $(options($(option),*))? + ) => { + /* compiler built-in */ + }; +} + +#[instruction_set(arm::a32)] +#[rustc_force_inline] +fn instruction_set_a32() {} + +#[instruction_set(arm::t32)] +#[rustc_force_inline] +fn instruction_set_t32() {} + +#[rustc_force_inline] +fn instruction_set_default() {} + +#[rustc_force_inline] +fn inline_always_and_using_inline_asm() { + unsafe { asm!("/* do nothing */") }; +} + +#[instruction_set(arm::t32)] +pub fn t32() { + instruction_set_a32(); +//~^ ERROR `instruction_set_a32` could not be inlined into `t32` but is required to be inlined + instruction_set_t32(); + instruction_set_default(); + inline_always_and_using_inline_asm(); +//~^ ERROR `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined +} + +pub fn default() { + instruction_set_a32(); +//~^ ERROR `instruction_set_a32` could not be inlined into `default` but is required to be inlined + instruction_set_t32(); +//~^ ERROR `instruction_set_t32` could not be inlined into `default` but is required to be inlined + instruction_set_default(); + inline_always_and_using_inline_asm(); +} diff --git a/tests/ui/force-inlining/asm.stderr b/tests/ui/force-inlining/asm.stderr new file mode 100644 index 0000000000000..ef04688965bb3 --- /dev/null +++ b/tests/ui/force-inlining/asm.stderr @@ -0,0 +1,34 @@ +error: `instruction_set_a32` could not be inlined into `t32` but is required to be inlined + --> $DIR/asm.rs:53:5 + | +LL | instruction_set_a32(); + | ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here + | + = note: could not be inlined due to: incompatible instruction set + +error: `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined + --> $DIR/asm.rs:57:5 + | +LL | inline_always_and_using_inline_asm(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...`inline_always_and_using_inline_asm` called here + | + = note: could not be inlined due to: cannot move inline-asm across instruction sets + +error: `instruction_set_a32` could not be inlined into `default` but is required to be inlined + --> $DIR/asm.rs:62:5 + | +LL | instruction_set_a32(); + | ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here + | + = note: could not be inlined due to: incompatible instruction set + +error: `instruction_set_t32` could not be inlined into `default` but is required to be inlined + --> $DIR/asm.rs:64:5 + | +LL | instruction_set_t32(); + | ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_t32` called here + | + = note: could not be inlined due to: incompatible instruction set + +error: aborting due to 4 previous errors + From 90066c0df3a564db756d9f7bd20a565f4675e267 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 10 Dec 2024 12:07:20 +0000 Subject: [PATCH 183/189] inline: remove unnecessary promoted check --- compiler/rustc_mir_transform/src/inline.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index a98901a668822..1f390200381ff 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -332,10 +332,6 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { } fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool { - if body.source.promoted.is_some() { - return false; - } - // Avoid inlining into coroutines, since their `optimized_mir` is used for layout computation, // which can create a cycle, even when no attempt is made to inline the function in the other // direction. From 5f316f5e0025ffa9ed31e01becf549fd73e61ed4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 12 Dec 2024 15:58:10 +0000 Subject: [PATCH 184/189] validator: move force inline check --- compiler/rustc_mir_transform/src/validate.rs | 33 ++++++-------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 9444c5b61dd67..035670d490309 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -80,7 +80,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { cfg_checker.fail(location, msg); } - if let MirPhase::Runtime(phase) = body.phase { + if let MirPhase::Runtime(_) = body.phase { if let ty::InstanceKind::Item(_) = body.source.instance { if body.has_free_regions() { cfg_checker.fail( @@ -89,27 +89,6 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { ); } } - - if phase >= RuntimePhase::Optimized - && body - .basic_blocks - .iter() - .filter_map(|bb| match &bb.terminator().kind { - TerminatorKind::Call { func, .. } - | TerminatorKind::TailCall { func, .. } => Some(func), - _ => None, - }) - .filter_map(|func| match func.ty(&body.local_decls, tcx).kind() { - ty::FnDef(did, ..) => Some(did), - _ => None, - }) - .any(|did| matches!(tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. })) - { - cfg_checker.fail( - Location::START, - "`#[rustc_force_inline]`-annotated function not inlined", - ); - } } } } @@ -388,7 +367,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_edge(location, *target, EdgeKind::Normal); self.check_unwind_edge(location, *unwind); } - TerminatorKind::Call { args, .. } | TerminatorKind::TailCall { args, .. } => { + TerminatorKind::Call { func, args, .. } + | TerminatorKind::TailCall { func, args, .. } => { // FIXME(explicit_tail_calls): refactor this & add tail-call specific checks if let TerminatorKind::Call { target, unwind, destination, .. } = terminator.kind { if let Some(target) = target { @@ -441,6 +421,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } } } + + if let ty::FnDef(did, ..) = func.ty(&self.body.local_decls, self.tcx).kind() + && self.body.phase >= MirPhase::Runtime(RuntimePhase::Optimized) + && matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. }) + { + self.fail(location, "`#[rustc_force_inline]`-annotated function not inlined"); + } } TerminatorKind::Assert { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); From dbec6bedf41d22a511d2d6a2637ff79ca75ec548 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 12 Dec 2024 15:58:24 +0000 Subject: [PATCH 185/189] inline: move should inline check --- compiler/rustc_mir_transform/src/inline.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1f390200381ff..44c6d8190f1a3 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -502,11 +502,6 @@ fn process_blocks<'tcx, I: Inliner<'tcx>>( let span = trace_span!("process_blocks", %callsite.callee, ?bb); let _guard = span.enter(); - if !inliner.should_inline_for_callee(callsite.callee.def_id()) { - debug!("not enabled"); - continue; - } - match try_inlining(inliner, caller_body, &callsite) { Err(reason) => { debug!("not-inlined {} [{}]", callsite.callee, reason); @@ -541,6 +536,11 @@ fn resolve_callsite<'tcx, I: Inliner<'tcx>>( if let TerminatorKind::Call { ref func, fn_span, .. } = terminator.kind { let func_ty = func.ty(caller_body, tcx); if let ty::FnDef(def_id, args) = *func_ty.kind() { + if !inliner.should_inline_for_callee(def_id) { + debug!("not enabled"); + return None; + } + // To resolve an instance its args have to be fully normalized. let args = tcx.try_normalize_erasing_regions(inliner.typing_env(), args).ok()?; let callee = From 3169a4493f23c2dc48b326e9c347955460fe5827 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 18 Dec 2024 13:37:13 +0000 Subject: [PATCH 186/189] don't collect `#[rustc_force_inline]` in eager mode --- compiler/rustc_monomorphize/src/collector.rs | 10 +++++---- ...d_code.caller.ForceInline.panic-abort.diff | 21 +++++++++++++++++++ ..._code.caller.ForceInline.panic-unwind.diff | 21 +++++++++++++++++++ tests/mir-opt/inline/forced_dead_code.rs | 17 +++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_dead_code.rs diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f3232a0e15d9a..416054d85fdba 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -225,8 +225,8 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths}; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, - TypeVisitableExt, VtblEntry, + self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Interner, Ty, TyCtxt, + TypeFoldable, TypeVisitableExt, VtblEntry, }; use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; @@ -965,7 +965,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - { // `#[rustc_force_inline]` items should never be codegened. This should be caught by // the MIR validator. - return false; + tcx.delay_bug("attempt to codegen `#[rustc_force_inline]` item"); } if def_id.is_local() { @@ -1462,7 +1462,9 @@ impl<'v> RootCollector<'_, 'v> { fn is_root(&self, def_id: LocalDefId) -> bool { !self.tcx.generics_of(def_id).requires_monomorphization(self.tcx) && match self.strategy { - MonoItemCollectionStrategy::Eager => true, + MonoItemCollectionStrategy::Eager => { + !matches!(self.tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. }) + } MonoItemCollectionStrategy::Lazy => { self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) diff --git a/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff new file mode 100644 index 0000000000000..f894f06e5a0ab --- /dev/null +++ b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined callee_forced) { ++ } + + bb0: { + StorageLive(_1); +- _1 = callee_forced() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff new file mode 100644 index 0000000000000..7b70fd665666a --- /dev/null +++ b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined callee_forced) { ++ } + + bb0: { + StorageLive(_1); +- _1 = callee_forced() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_dead_code.rs b/tests/mir-opt/inline/forced_dead_code.rs new file mode 100644 index 0000000000000..832272cde7f0a --- /dev/null +++ b/tests/mir-opt/inline/forced_dead_code.rs @@ -0,0 +1,17 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 -Clink-dead-code +#![feature(rustc_attrs)] + +#[rustc_force_inline] +pub fn callee_forced() {} + +// EMIT_MIR forced_dead_code.caller.ForceInline.diff +pub fn caller() { + callee_forced(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined callee_forced) +} + +fn main() { + caller(); +} From ce602acfc22724c30b6154f650225d2e1d1550ed Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 18 Dec 2024 13:54:41 +0000 Subject: [PATCH 187/189] clarify `target_feature` + forced inlining --- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a78826a462945..37b53bb5bea47 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -627,17 +627,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // enabled. For that reason we also forbid `#[inline(always)]` as it can't be // respected. // - // `#[rustc_force_inline]` doesn't need to be prohibited here, that - // is implemented entirely in rustc can attempt to inline and error if it cannot. + // `#[rustc_force_inline]` doesn't need to be prohibited here, only + // `#[inline(always)]`, as forced inlining is implemented entirely within + // rustc (and so the MIR inliner can do any necessary checks for compatible target + // features). + // + // This sidesteps the LLVM blockers in enabling `target_features` + + // `inline(always)` to be used together (see rust-lang/rust#116573 and + // llvm/llvm-project#70563). if !codegen_fn_attrs.target_features.is_empty() && matches!(codegen_fn_attrs.inline, InlineAttr::Always) { if let Some(span) = inline_span { - tcx.dcx().span_err( - span, - "cannot use `#[inline(always)]` with \ - `#[target_feature]`", - ); + tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`"); } } From cc9a9ecccb2fbbb7687ed076e06411c2f4ac5fbb Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 7 Jan 2025 11:27:04 +0000 Subject: [PATCH 188/189] mir_build: check annotated functions w/out callers --- Cargo.lock | 1 + compiler/rustc_mir_build/Cargo.toml | 1 + compiler/rustc_mir_build/messages.ftl | 6 ++ compiler/rustc_mir_build/src/builder/mod.rs | 2 + compiler/rustc_mir_build/src/check_inline.rs | 81 ++++++++++++++++++++ compiler/rustc_mir_build/src/errors.rs | 12 +++ compiler/rustc_mir_build/src/lib.rs | 1 + compiler/rustc_mir_transform/src/inline.rs | 52 ++----------- tests/ui/force-inlining/deny-async.rs | 5 +- tests/ui/force-inlining/deny-async.stderr | 27 ++++--- tests/ui/force-inlining/deny-closure.rs | 7 +- tests/ui/force-inlining/deny-closure.stderr | 36 ++++----- tests/ui/force-inlining/deny.rs | 7 +- tests/ui/force-inlining/deny.stderr | 27 ++++--- tests/ui/force-inlining/early-deny.rs | 21 +++++ tests/ui/force-inlining/early-deny.stderr | 35 +++++++++ 16 files changed, 223 insertions(+), 98 deletions(-) create mode 100644 compiler/rustc_mir_build/src/check_inline.rs create mode 100644 tests/ui/force-inlining/early-deny.rs create mode 100644 tests/ui/force-inlining/early-deny.stderr diff --git a/Cargo.lock b/Cargo.lock index 0cab392454e5b..117f1475e000a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4158,6 +4158,7 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 119047227431d..1f3689926bcf3 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -12,6 +12,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 5d61a9d1e752a..5203c33c968fb 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -118,6 +118,12 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior .label = use of extern static +mir_build_force_inline = + `{$callee}` is incompatible with `#[rustc_force_inline]` + .attr = annotation here + .callee = `{$callee}` defined here + .note = incompatible due to: {$reason} + mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant mir_build_initializing_type_with_requires_unsafe = diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 932b6fbe026ec..8b01ec0d06af1 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -29,6 +29,7 @@ use rustc_span::{Span, Symbol, sym}; use super::lints; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::scope::DropKind; +use crate::check_inline; pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( tcx: TyCtxt<'tcx>, @@ -80,6 +81,7 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx }; lints::check(tcx, &body); + check_inline::check_force_inline(tcx, &body); // The borrow checker will replace all the regions here with its own // inference variables. There's no point having non-erased regions here. diff --git a/compiler/rustc_mir_build/src/check_inline.rs b/compiler/rustc_mir_build/src/check_inline.rs new file mode 100644 index 0000000000000..1af3b3e2c1353 --- /dev/null +++ b/compiler/rustc_mir_build/src/check_inline.rs @@ -0,0 +1,81 @@ +use rustc_attr_parsing::InlineAttr; +use rustc_hir::def_id::DefId; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::{Body, TerminatorKind}; +use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; +use rustc_span::sym; + +/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its +/// definition alone (irrespective of any specific caller). +pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id(); + if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { + return; + } + let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { + return; + }; + + if let Err(reason) = + is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) + { + tcx.dcx().emit_err(crate::errors::InvalidForceInline { + attr_span, + callee_span: tcx.def_span(def_id), + callee: tcx.def_path_str(def_id), + reason, + }); + } +} + +pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> { + let codegen_attrs = tcx.codegen_fn_attrs(def_id); + if tcx.has_attr(def_id, sym::rustc_no_mir_inline) { + return Err("#[rustc_no_mir_inline]"); + } + + // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined + // MIR correctly when Modified Condition/Decision Coverage is enabled. + if tcx.sess.instrument_coverage_mcdc() { + return Err("incompatible with MC/DC coverage"); + } + + let ty = tcx.type_of(def_id); + if match ty.instantiate_identity().kind() { + ty::FnDef(..) => tcx.fn_sig(def_id).instantiate_identity().c_variadic(), + ty::Closure(_, args) => args.as_closure().sig().c_variadic(), + _ => false, + } { + return Err("C variadic"); + } + + if codegen_attrs.flags.contains(CodegenFnAttrFlags::COLD) { + return Err("cold"); + } + + // Intrinsic fallback bodies are automatically made cross-crate inlineable, + // but at this stage we don't know whether codegen knows the intrinsic, + // so just conservatively don't inline it. This also ensures that we do not + // accidentally inline the body of an intrinsic that *must* be overridden. + if tcx.has_attr(def_id, sym::rustc_intrinsic) { + return Err("callee is an intrinsic"); + } + + Ok(()) +} + +pub fn is_inline_valid_on_body<'tcx>( + _: TyCtxt<'tcx>, + body: &Body<'tcx>, +) -> Result<(), &'static str> { + if body + .basic_blocks + .iter() + .any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. })) + { + return Err("can't inline functions with tail calls"); + } + + Ok(()) +} diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 790d56860d28e..90c31a2caa326 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1107,3 +1107,15 @@ impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> { ); } } + +#[derive(Diagnostic)] +#[diag(mir_build_force_inline)] +#[note] +pub(crate) struct InvalidForceInline { + #[primary_span] + pub attr_span: Span, + #[label(mir_build_callee)] + pub callee_span: Span, + pub callee: String, + pub reason: &'static str, +} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 467725841dcd0..76a35355de72a 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -15,6 +15,7 @@ // "Go to file" feature to silently ignore all files in the module, probably // because it assumes that "build" is a build-output directory. See #134365. mod builder; +pub mod check_inline; mod check_tail_calls; mod check_unsafety; mod errors; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 44c6d8190f1a3..e4daa2b9757e7 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -10,13 +10,12 @@ use rustc_hir::def_id::DefId; use rustc_index::Idx; use rustc_index::bit_set::BitSet; use rustc_middle::bug; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; -use rustc_span::sym; use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::CostChecker; @@ -120,7 +119,6 @@ trait Inliner<'tcx> { callsite: &CallSite<'tcx>, callee_body: &Body<'tcx>, callee_attrs: &CodegenFnAttrs, - cross_crate_inlinable: bool, ) -> Result<(), &'static str>; // How many callsites in a body are we allowed to inline? We need to limit this in order @@ -196,7 +194,6 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { _: &CallSite<'tcx>, callee_body: &Body<'tcx>, callee_attrs: &CodegenFnAttrs, - _: bool, ) -> Result<(), &'static str> { if callee_body.tainted_by_errors.is_some() { return Err("body has errors"); @@ -215,14 +212,6 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { // inline-asm is detected. LLVM will still possibly do an inline later on // if the no-attribute function ends up with the same instruction set anyway. Err("cannot move inline-asm across instruction sets") - } else if callee_body - .basic_blocks - .iter() - .any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. })) - { - // FIXME(explicit_tail_calls): figure out how exactly functions containing tail - // calls can be inlined (and if they even should) - Err("can't inline functions with tail calls") } else { Ok(()) } @@ -348,7 +337,6 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { callsite: &CallSite<'tcx>, callee_body: &Body<'tcx>, callee_attrs: &CodegenFnAttrs, - cross_crate_inlinable: bool, ) -> Result<(), &'static str> { let tcx = self.tcx(); @@ -358,7 +346,7 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { let mut threshold = if self.caller_is_inline_forwarder { tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30) - } else if cross_crate_inlinable { + } else if tcx.cross_crate_inlinable(callsite.callee.def_id()) { tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) } else { tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50) @@ -587,16 +575,8 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( check_mir_is_available(inliner, caller_body, callsite.callee)?; let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id()); - let cross_crate_inlinable = tcx.cross_crate_inlinable(callsite.callee.def_id()); - check_codegen_attributes(inliner, callsite, callee_attrs, cross_crate_inlinable)?; - - // Intrinsic fallback bodies are automatically made cross-crate inlineable, - // but at this stage we don't know whether codegen knows the intrinsic, - // so just conservatively don't inline it. This also ensures that we do not - // accidentally inline the body of an intrinsic that *must* be overridden. - if tcx.has_attr(callsite.callee.def_id(), sym::rustc_intrinsic) { - return Err("callee is an intrinsic"); - } + rustc_mir_build::check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; + check_codegen_attributes(inliner, callsite, callee_attrs)?; let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; @@ -610,7 +590,8 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( } let callee_body = try_instance_mir(tcx, callsite.callee.def)?; - inliner.check_callee_mir_body(callsite, callee_body, callee_attrs, cross_crate_inlinable)?; + rustc_mir_build::check_inline::is_inline_valid_on_body(tcx, callee_body)?; + inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?; let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( tcx, @@ -775,38 +756,19 @@ fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>( inliner: &I, callsite: &CallSite<'tcx>, callee_attrs: &CodegenFnAttrs, - cross_crate_inlinable: bool, ) -> Result<(), &'static str> { let tcx = inliner.tcx(); - if tcx.has_attr(callsite.callee.def_id(), sym::rustc_no_mir_inline) { - return Err("#[rustc_no_mir_inline]"); - } - if let InlineAttr::Never = callee_attrs.inline { return Err("never inline attribute"); } - // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined - // MIR correctly when Modified Condition/Decision Coverage is enabled. - if tcx.sess.instrument_coverage_mcdc() { - return Err("incompatible with MC/DC coverage"); - } - // Reachability pass defines which functions are eligible for inlining. Generally inlining // other functions is incorrect because they could reference symbols that aren't exported. let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); - if !is_generic && !cross_crate_inlinable { + if !is_generic && !tcx.cross_crate_inlinable(callsite.callee.def_id()) { return Err("not exported"); } - if callsite.fn_sig.c_variadic() { - return Err("C variadic"); - } - - if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) { - return Err("cold"); - } - let codegen_fn_attrs = tcx.codegen_fn_attrs(inliner.caller_def_id()); if callee_attrs.no_sanitize != codegen_fn_attrs.no_sanitize { return Err("incompatible sanitizer set"); diff --git a/tests/ui/force-inlining/deny-async.rs b/tests/ui/force-inlining/deny-async.rs index d5b6dc000f70d..bdf6271bd2a11 100644 --- a/tests/ui/force-inlining/deny-async.rs +++ b/tests/ui/force-inlining/deny-async.rs @@ -8,18 +8,17 @@ #[rustc_no_mir_inline] #[rustc_force_inline] +//~^ ERROR `callee` is incompatible with `#[rustc_force_inline]` pub fn callee() { } #[rustc_no_mir_inline] #[rustc_force_inline = "the test requires it"] +//~^ ERROR `callee_justified` is incompatible with `#[rustc_force_inline]` pub fn callee_justified() { } async fn async_caller() { callee(); -//~^ ERROR `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined - callee_justified(); -//~^ ERROR `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined } diff --git a/tests/ui/force-inlining/deny-async.stderr b/tests/ui/force-inlining/deny-async.stderr index 7b077174ee89e..302ca4190710b 100644 --- a/tests/ui/force-inlining/deny-async.stderr +++ b/tests/ui/force-inlining/deny-async.stderr @@ -1,19 +1,24 @@ -error: `callee` could not be inlined into `async_caller::{closure#0}` but is required to be inlined - --> $DIR/deny-async.rs:20:5 +error: `callee` is incompatible with `#[rustc_force_inline]` + --> $DIR/deny-async.rs:10:1 | -LL | callee(); - | ^^^^^^^^ ...`callee` called here +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn callee() { + | --------------- `callee` defined here | - = note: could not be inlined due to: #[rustc_no_mir_inline] + = note: incompatible due to: #[rustc_no_mir_inline] -error: `callee_justified` could not be inlined into `async_caller::{closure#0}` but is required to be inlined - --> $DIR/deny-async.rs:23:5 +error: `callee_justified` is incompatible with `#[rustc_force_inline]` + --> $DIR/deny-async.rs:16:1 | -LL | callee_justified(); - | ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here +LL | #[rustc_force_inline = "the test requires it"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn callee_justified() { + | ------------------------- `callee_justified` defined here | - = note: could not be inlined due to: #[rustc_no_mir_inline] - = note: `callee_justified` is required to be inlined to: the test requires it + = note: incompatible due to: #[rustc_no_mir_inline] error: aborting due to 2 previous errors diff --git a/tests/ui/force-inlining/deny-closure.rs b/tests/ui/force-inlining/deny-closure.rs index 0057f1e78540c..31314c450fcf1 100644 --- a/tests/ui/force-inlining/deny-closure.rs +++ b/tests/ui/force-inlining/deny-closure.rs @@ -1,4 +1,4 @@ -//@ build-fail +//@ check-fail //@ compile-flags: --crate-type=lib #![allow(internal_features)] #![feature(rustc_attrs)] @@ -7,20 +7,19 @@ #[rustc_no_mir_inline] #[rustc_force_inline] +//~^ ERROR `callee` is incompatible with `#[rustc_force_inline]` pub fn callee() { } #[rustc_no_mir_inline] #[rustc_force_inline = "the test requires it"] +//~^ ERROR `callee_justified` is incompatible with `#[rustc_force_inline]` pub fn callee_justified() { } pub fn caller() { (|| { callee(); -//~^ ERROR `callee` could not be inlined into `caller::{closure#0}` but is required to be inlined - callee_justified(); -//~^ ERROR `callee_justified` could not be inlined into `caller::{closure#0}` but is required to be inlined })(); } diff --git a/tests/ui/force-inlining/deny-closure.stderr b/tests/ui/force-inlining/deny-closure.stderr index 7d42145f1c878..e657a29542023 100644 --- a/tests/ui/force-inlining/deny-closure.stderr +++ b/tests/ui/force-inlining/deny-closure.stderr @@ -1,28 +1,24 @@ -error: `callee` could not be inlined into `caller::{closure#0}` but is required to be inlined - --> $DIR/deny-closure.rs:20:9 +error: `callee` is incompatible with `#[rustc_force_inline]` + --> $DIR/deny-closure.rs:9:1 | -LL | callee(); - | ^^^^^^^^ ...`callee` called here +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn callee() { + | --------------- `callee` defined here | - = note: could not be inlined due to: #[rustc_no_mir_inline] + = note: incompatible due to: #[rustc_no_mir_inline] -error: `callee_justified` could not be inlined into `caller::{closure#0}` but is required to be inlined - --> $DIR/deny-closure.rs:23:9 +error: `callee_justified` is incompatible with `#[rustc_force_inline]` + --> $DIR/deny-closure.rs:15:1 | -LL | callee_justified(); - | ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here +LL | #[rustc_force_inline = "the test requires it"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn callee_justified() { + | ------------------------- `callee_justified` defined here | - = note: could not be inlined due to: #[rustc_no_mir_inline] - = note: `callee_justified` is required to be inlined to: the test requires it - -note: the above error was encountered while instantiating `fn caller::{closure#0}` - --> $DIR/deny-closure.rs:19:5 - | -LL | / (|| { -LL | | callee(); -... | -LL | | })(); - | |________^ + = note: incompatible due to: #[rustc_no_mir_inline] error: aborting due to 2 previous errors diff --git a/tests/ui/force-inlining/deny.rs b/tests/ui/force-inlining/deny.rs index a19e820cff28d..7712f5f50f316 100644 --- a/tests/ui/force-inlining/deny.rs +++ b/tests/ui/force-inlining/deny.rs @@ -1,4 +1,4 @@ -//@ build-fail +//@ check-fail //@ compile-flags: --crate-type=lib #![allow(internal_features)] #![feature(rustc_attrs)] @@ -7,18 +7,17 @@ #[rustc_no_mir_inline] #[rustc_force_inline] +//~^ ERROR `callee` is incompatible with `#[rustc_force_inline]` pub fn callee() { } #[rustc_no_mir_inline] #[rustc_force_inline = "the test requires it"] +//~^ ERROR `callee_justified` is incompatible with `#[rustc_force_inline]` pub fn callee_justified() { } pub fn caller() { callee(); -//~^ ERROR `callee` could not be inlined into `caller` but is required to be inlined - callee_justified(); -//~^ ERROR `callee_justified` could not be inlined into `caller` but is required to be inlined } diff --git a/tests/ui/force-inlining/deny.stderr b/tests/ui/force-inlining/deny.stderr index 3983bead182eb..c276fa28ba895 100644 --- a/tests/ui/force-inlining/deny.stderr +++ b/tests/ui/force-inlining/deny.stderr @@ -1,19 +1,24 @@ -error: `callee` could not be inlined into `caller` but is required to be inlined - --> $DIR/deny.rs:19:5 +error: `callee` is incompatible with `#[rustc_force_inline]` + --> $DIR/deny.rs:9:1 | -LL | callee(); - | ^^^^^^^^ ...`callee` called here +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn callee() { + | --------------- `callee` defined here | - = note: could not be inlined due to: #[rustc_no_mir_inline] + = note: incompatible due to: #[rustc_no_mir_inline] -error: `callee_justified` could not be inlined into `caller` but is required to be inlined - --> $DIR/deny.rs:22:5 +error: `callee_justified` is incompatible with `#[rustc_force_inline]` + --> $DIR/deny.rs:15:1 | -LL | callee_justified(); - | ^^^^^^^^^^^^^^^^^^ ...`callee_justified` called here +LL | #[rustc_force_inline = "the test requires it"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn callee_justified() { + | ------------------------- `callee_justified` defined here | - = note: could not be inlined due to: #[rustc_no_mir_inline] - = note: `callee_justified` is required to be inlined to: the test requires it + = note: incompatible due to: #[rustc_no_mir_inline] error: aborting due to 2 previous errors diff --git a/tests/ui/force-inlining/early-deny.rs b/tests/ui/force-inlining/early-deny.rs new file mode 100644 index 0000000000000..99b03a4e0e2ce --- /dev/null +++ b/tests/ui/force-inlining/early-deny.rs @@ -0,0 +1,21 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib +#![feature(c_variadic)] +#![feature(rustc_attrs)] + +#[rustc_no_mir_inline] +#[rustc_force_inline] +//~^ ERROR `rustc_attr` is incompatible with `#[rustc_force_inline]` +pub fn rustc_attr() { +} + +#[cold] +#[rustc_force_inline] +//~^ ERROR `cold` is incompatible with `#[rustc_force_inline]` +pub fn cold() { +} + +#[rustc_force_inline] +//~^ ERROR `variadic` is incompatible with `#[rustc_force_inline]` +pub unsafe extern "C" fn variadic(args: ...) { +} diff --git a/tests/ui/force-inlining/early-deny.stderr b/tests/ui/force-inlining/early-deny.stderr new file mode 100644 index 0000000000000..abee66fd293c6 --- /dev/null +++ b/tests/ui/force-inlining/early-deny.stderr @@ -0,0 +1,35 @@ +error: `rustc_attr` is incompatible with `#[rustc_force_inline]` + --> $DIR/early-deny.rs:7:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn rustc_attr() { + | ------------------- `rustc_attr` defined here + | + = note: incompatible due to: #[rustc_no_mir_inline] + +error: `cold` is incompatible with `#[rustc_force_inline]` + --> $DIR/early-deny.rs:13:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub fn cold() { + | ------------- `cold` defined here + | + = note: incompatible due to: cold + +error: `variadic` is incompatible with `#[rustc_force_inline]` + --> $DIR/early-deny.rs:18:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | pub unsafe extern "C" fn variadic(args: ...) { + | -------------------------------------------- `variadic` defined here + | + = note: incompatible due to: C variadic + +error: aborting due to 3 previous errors + From cd24a904931753639890311d2c3b475b800df6d2 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 10 Jan 2025 17:13:58 -0500 Subject: [PATCH 189/189] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index fd784878cfa84..088d496082726 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit fd784878cfa843e3e29a6654ecf564c62fae6735 +Subproject commit 088d496082726091024f1689c124a0c3dccbd775